github.com/marconiprotocol/go-methereum-lite@v0.0.0-20190918214227-3cd8b06fcf99/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/MarconiProtocol/go-methereum-lite/accounts" 32 "github.com/MarconiProtocol/go-methereum-lite/accounts/keystore" 33 "github.com/MarconiProtocol/go-methereum-lite/common" 34 "github.com/MarconiProtocol/go-methereum-lite/common/fdlimit" 35 "github.com/MarconiProtocol/go-methereum-lite/consensus" 36 "github.com/MarconiProtocol/go-methereum-lite/consensus/clique" 37 "github.com/MarconiProtocol/go-methereum-lite/consensus/ethash" 38 "github.com/MarconiProtocol/go-methereum-lite/core" 39 "github.com/MarconiProtocol/go-methereum-lite/core/state" 40 "github.com/MarconiProtocol/go-methereum-lite/core/vm" 41 "github.com/MarconiProtocol/go-methereum-lite/crypto" 42 "github.com/MarconiProtocol/go-methereum-lite/dashboard" 43 "github.com/MarconiProtocol/go-methereum-lite/eth" 44 "github.com/MarconiProtocol/go-methereum-lite/eth/downloader" 45 "github.com/MarconiProtocol/go-methereum-lite/eth/gasprice" 46 "github.com/MarconiProtocol/go-methereum-lite/ethdb" 47 "github.com/MarconiProtocol/go-methereum-lite/ethstats" 48 "github.com/MarconiProtocol/go-methereum-lite/les" 49 "github.com/MarconiProtocol/go-methereum-lite/log" 50 "github.com/MarconiProtocol/go-methereum-lite/metrics" 51 "github.com/MarconiProtocol/go-methereum-lite/metrics/influxdb" 52 "github.com/MarconiProtocol/go-methereum-lite/node" 53 "github.com/MarconiProtocol/go-methereum-lite/p2p" 54 "github.com/MarconiProtocol/go-methereum-lite/p2p/discv5" 55 "github.com/MarconiProtocol/go-methereum-lite/p2p/enode" 56 "github.com/MarconiProtocol/go-methereum-lite/p2p/nat" 57 "github.com/MarconiProtocol/go-methereum-lite/p2p/netutil" 58 "github.com/MarconiProtocol/go-methereum-lite/params" 59 whisper "github.com/MarconiProtocol/go-methereum-lite/whisper/whisperv6" 60 cli "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 KeyStoreDirFlag = DirectoryFlag{ 123 Name: "keystore", 124 Usage: "Directory for the keystore (default = inside the datadir)", 125 } 126 NoUSBFlag = cli.BoolFlag{ 127 Name: "nousb", 128 Usage: "Disables monitoring for and managing USB hardware wallets", 129 } 130 NetworkIdFlag = cli.Uint64Flag{ 131 Name: "networkid", 132 Usage: "Network identifier (integer, 161027=Marconi)", 133 Value: eth.DefaultConfig.NetworkId, 134 } 135 TestnetFlag = cli.BoolFlag{ 136 Name: "testnet", 137 Usage: "Ropsten network: pre-configured proof-of-work test network", 138 } 139 RinkebyFlag = cli.BoolFlag{ 140 Name: "rinkeby", 141 Usage: "Rinkeby network: pre-configured proof-of-authority test network", 142 } 143 GoerliFlag = cli.BoolFlag{ 144 Name: "goerli", 145 Usage: "Görli 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 ethashPowMode string = "ethash" 424 quickTestPowMode string = "quick_test" 425 cryptonightPowMode string = "cryptonight" 426 PowModeFlag = cli.StringFlag{ 427 Name: "powmode", 428 Usage: "Which proof-of-work hash function to use for both mining and verification. Can be one of 'ethash', 'quick_test', or 'cryptonight'.", 429 Value: "cryptonight", 430 } 431 NoCompactionFlag = cli.BoolFlag{ 432 Name: "nocompaction", 433 Usage: "Disables db compaction after import", 434 } 435 // RPC settings 436 RPCEnabledFlag = cli.BoolFlag{ 437 Name: "rpc", 438 Usage: "Enable the HTTP-RPC server", 439 } 440 RPCListenAddrFlag = cli.StringFlag{ 441 Name: "rpcaddr", 442 Usage: "HTTP-RPC server listening interface", 443 Value: node.DefaultHTTPHost, 444 } 445 RPCPortFlag = cli.IntFlag{ 446 Name: "rpcport", 447 Usage: "HTTP-RPC server listening port", 448 Value: node.DefaultHTTPPort, 449 } 450 RPCCORSDomainFlag = cli.StringFlag{ 451 Name: "rpccorsdomain", 452 Usage: "Comma separated list of domains from which to accept cross origin requests (browser enforced)", 453 Value: "", 454 } 455 RPCVirtualHostsFlag = cli.StringFlag{ 456 Name: "rpcvhosts", 457 Usage: "Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard.", 458 Value: strings.Join(node.DefaultConfig.HTTPVirtualHosts, ","), 459 } 460 RPCApiFlag = cli.StringFlag{ 461 Name: "rpcapi", 462 Usage: "API's offered over the HTTP-RPC interface", 463 Value: "", 464 } 465 IPCDisabledFlag = cli.BoolFlag{ 466 Name: "ipcdisable", 467 Usage: "Disable the IPC-RPC server", 468 } 469 IPCPathFlag = DirectoryFlag{ 470 Name: "ipcpath", 471 Usage: "Filename for IPC socket/pipe within the datadir (explicit paths escape it)", 472 } 473 WSEnabledFlag = cli.BoolFlag{ 474 Name: "ws", 475 Usage: "Enable the WS-RPC server", 476 } 477 WSListenAddrFlag = cli.StringFlag{ 478 Name: "wsaddr", 479 Usage: "WS-RPC server listening interface", 480 Value: node.DefaultWSHost, 481 } 482 WSPortFlag = cli.IntFlag{ 483 Name: "wsport", 484 Usage: "WS-RPC server listening port", 485 Value: node.DefaultWSPort, 486 } 487 WSApiFlag = cli.StringFlag{ 488 Name: "wsapi", 489 Usage: "API's offered over the WS-RPC interface", 490 Value: "", 491 } 492 WSAllowedOriginsFlag = cli.StringFlag{ 493 Name: "wsorigins", 494 Usage: "Origins from which to accept websockets requests", 495 Value: "", 496 } 497 ExecFlag = cli.StringFlag{ 498 Name: "exec", 499 Usage: "Execute JavaScript statement", 500 } 501 PreloadJSFlag = cli.StringFlag{ 502 Name: "preload", 503 Usage: "Comma separated list of JavaScript files to preload into the console", 504 } 505 506 // Network Settings 507 MaxPeersFlag = cli.IntFlag{ 508 Name: "maxpeers", 509 Usage: "Maximum number of network peers (network disabled if set to 0)", 510 Value: 25, 511 } 512 MaxPendingPeersFlag = cli.IntFlag{ 513 Name: "maxpendpeers", 514 Usage: "Maximum number of pending connection attempts (defaults used if set to 0)", 515 Value: 0, 516 } 517 ListenPortFlag = cli.IntFlag{ 518 Name: "port", 519 Usage: "Network listening port", 520 Value: 13200, 521 } 522 BootnodesFlag = cli.StringFlag{ 523 Name: "bootnodes", 524 Usage: "Comma separated enode URLs for P2P discovery bootstrap (set v4+v5 instead for light servers)", 525 Value: "", 526 } 527 BootnodesV4Flag = cli.StringFlag{ 528 Name: "bootnodesv4", 529 Usage: "Comma separated enode URLs for P2P v4 discovery bootstrap (light server, full nodes)", 530 Value: "", 531 } 532 BootnodesV5Flag = cli.StringFlag{ 533 Name: "bootnodesv5", 534 Usage: "Comma separated enode URLs for P2P v5 discovery bootstrap (light server, light nodes)", 535 Value: "", 536 } 537 NodeKeyFileFlag = cli.StringFlag{ 538 Name: "nodekey", 539 Usage: "P2P node key file", 540 } 541 NodeKeyHexFlag = cli.StringFlag{ 542 Name: "nodekeyhex", 543 Usage: "P2P node key as hex (for testing)", 544 } 545 NATFlag = cli.StringFlag{ 546 Name: "nat", 547 Usage: "NAT port mapping mechanism (any|none|upnp|pmp|extip:<IP>)", 548 Value: "any", 549 } 550 NoDiscoverFlag = cli.BoolFlag{ 551 Name: "nodiscover", 552 Usage: "Disables the peer discovery mechanism (manual peer addition)", 553 } 554 DiscoveryV5Flag = cli.BoolFlag{ 555 Name: "v5disc", 556 Usage: "Enables the experimental RLPx V5 (Topic Discovery) mechanism", 557 } 558 NetrestrictFlag = cli.StringFlag{ 559 Name: "netrestrict", 560 Usage: "Restricts network communication to the given IP networks (CIDR masks)", 561 } 562 563 // ATM the url is left to the user and deployment to 564 JSpathFlag = cli.StringFlag{ 565 Name: "jspath", 566 Usage: "JavaScript root path for `loadScript`", 567 Value: ".", 568 } 569 570 // Gas price oracle settings 571 GpoBlocksFlag = cli.IntFlag{ 572 Name: "gpoblocks", 573 Usage: "Number of recent blocks to check for gas prices", 574 Value: eth.DefaultConfig.GPO.Blocks, 575 } 576 GpoPercentileFlag = cli.IntFlag{ 577 Name: "gpopercentile", 578 Usage: "Suggested gas price is the given percentile of a set of recent transaction gas prices", 579 Value: eth.DefaultConfig.GPO.Percentile, 580 } 581 WhisperEnabledFlag = cli.BoolFlag{ 582 Name: "shh", 583 Usage: "Enable Whisper", 584 } 585 WhisperMaxMessageSizeFlag = cli.IntFlag{ 586 Name: "shh.maxmessagesize", 587 Usage: "Max message size accepted", 588 Value: int(whisper.DefaultMaxMessageSize), 589 } 590 WhisperMinPOWFlag = cli.Float64Flag{ 591 Name: "shh.pow", 592 Usage: "Minimum POW accepted", 593 Value: whisper.DefaultMinimumPoW, 594 } 595 WhisperRestrictConnectionBetweenLightClientsFlag = cli.BoolFlag{ 596 Name: "shh.restrict-light", 597 Usage: "Restrict connection between two whisper light clients", 598 } 599 600 // Metrics flags 601 MetricsEnabledFlag = cli.BoolFlag{ 602 Name: metrics.MetricsEnabledFlag, 603 Usage: "Enable metrics collection and reporting", 604 } 605 MetricsEnableInfluxDBFlag = cli.BoolFlag{ 606 Name: "metrics.influxdb", 607 Usage: "Enable metrics export/push to an external InfluxDB database", 608 } 609 MetricsInfluxDBEndpointFlag = cli.StringFlag{ 610 Name: "metrics.influxdb.endpoint", 611 Usage: "InfluxDB API endpoint to report metrics to", 612 Value: "http://localhost:8086", 613 } 614 MetricsInfluxDBDatabaseFlag = cli.StringFlag{ 615 Name: "metrics.influxdb.database", 616 Usage: "InfluxDB database name to push reported metrics to", 617 Value: "geth", 618 } 619 MetricsInfluxDBUsernameFlag = cli.StringFlag{ 620 Name: "metrics.influxdb.username", 621 Usage: "Username to authorize access to the database", 622 Value: "test", 623 } 624 MetricsInfluxDBPasswordFlag = cli.StringFlag{ 625 Name: "metrics.influxdb.password", 626 Usage: "Password to authorize access to the database", 627 Value: "test", 628 } 629 // Tags are part of every measurement sent to InfluxDB. Queries on tags are faster in InfluxDB. 630 // For example `host` tag could be used so that we can group all nodes and average a measurement 631 // across all of them, but also so that we can select a specific node and inspect its measurements. 632 // https://docs.influxdata.com/influxdb/v1.4/concepts/key_concepts/#tag-key 633 MetricsInfluxDBTagsFlag = cli.StringFlag{ 634 Name: "metrics.influxdb.tags", 635 Usage: "Comma-separated InfluxDB tags (key/values) attached to all measurements", 636 Value: "host=localhost", 637 } 638 639 EWASMInterpreterFlag = cli.StringFlag{ 640 Name: "vm.ewasm", 641 Usage: "External ewasm configuration (default = built-in interpreter)", 642 Value: "", 643 } 644 EVMInterpreterFlag = cli.StringFlag{ 645 Name: "vm.evm", 646 Usage: "External EVM configuration (default = built-in interpreter)", 647 Value: "", 648 } 649 ) 650 651 // MakeDataDir retrieves the currently requested data directory, terminating 652 // if none (or the empty string) is specified. If the node is starting a testnet, 653 // the a subdirectory of the specified datadir will be used. 654 func MakeDataDir(ctx *cli.Context) string { 655 if path := ctx.GlobalString(DataDirFlag.Name); path != "" { 656 if ctx.GlobalBool(TestnetFlag.Name) { 657 return filepath.Join(path, "testnet") 658 } 659 if ctx.GlobalBool(RinkebyFlag.Name) { 660 return filepath.Join(path, "rinkeby") 661 } 662 if ctx.GlobalBool(GoerliFlag.Name) { 663 return filepath.Join(path, "goerli") 664 } 665 return path 666 } 667 Fatalf("Cannot determine default data directory, please set manually (--datadir)") 668 return "" 669 } 670 671 // setNodeKey creates a node key from set command line flags, either loading it 672 // from a file or as a specified hex value. If neither flags were provided, this 673 // method returns nil and an emphemeral key is to be generated. 674 func setNodeKey(ctx *cli.Context, cfg *p2p.Config) { 675 var ( 676 hex = ctx.GlobalString(NodeKeyHexFlag.Name) 677 file = ctx.GlobalString(NodeKeyFileFlag.Name) 678 key *ecdsa.PrivateKey 679 err error 680 ) 681 switch { 682 case file != "" && hex != "": 683 Fatalf("Options %q and %q are mutually exclusive", NodeKeyFileFlag.Name, NodeKeyHexFlag.Name) 684 case file != "": 685 if key, err = crypto.LoadECDSA(file); err != nil { 686 Fatalf("Option %q: %v", NodeKeyFileFlag.Name, err) 687 } 688 cfg.PrivateKey = key 689 case hex != "": 690 if key, err = crypto.HexToECDSA(hex); err != nil { 691 Fatalf("Option %q: %v", NodeKeyHexFlag.Name, err) 692 } 693 cfg.PrivateKey = key 694 } 695 } 696 697 // setNodeUserIdent creates the user identifier from CLI flags. 698 func setNodeUserIdent(ctx *cli.Context, cfg *node.Config) { 699 if identity := ctx.GlobalString(IdentityFlag.Name); len(identity) > 0 { 700 cfg.UserIdent = identity 701 } 702 } 703 704 // setBootstrapNodes creates a list of bootstrap nodes from the command line 705 // flags, reverting to pre-configured ones if none have been specified. 706 func setBootstrapNodes(ctx *cli.Context, cfg *p2p.Config) { 707 urls := params.MainnetBootnodes 708 switch { 709 case ctx.GlobalIsSet(BootnodesFlag.Name) || ctx.GlobalIsSet(BootnodesV4Flag.Name): 710 if ctx.GlobalIsSet(BootnodesV4Flag.Name) { 711 urls = strings.Split(ctx.GlobalString(BootnodesV4Flag.Name), ",") 712 } else { 713 urls = strings.Split(ctx.GlobalString(BootnodesFlag.Name), ",") 714 } 715 case ctx.GlobalBool(TestnetFlag.Name): 716 urls = params.TestnetBootnodes 717 case ctx.GlobalBool(RinkebyFlag.Name): 718 urls = params.RinkebyBootnodes 719 case ctx.GlobalBool(GoerliFlag.Name): 720 urls = params.GoerliBootnodes 721 case cfg.BootstrapNodes != nil: 722 return // already set, don't apply defaults. 723 } 724 725 cfg.BootstrapNodes = make([]*enode.Node, 0, len(urls)) 726 for _, url := range urls { 727 node, err := enode.ParseV4(url) 728 if err != nil { 729 log.Crit("Bootstrap URL invalid", "enode", url, "err", err) 730 } 731 cfg.BootstrapNodes = append(cfg.BootstrapNodes, node) 732 } 733 } 734 735 // setBootstrapNodesV5 creates a list of bootstrap nodes from the command line 736 // flags, reverting to pre-configured ones if none have been specified. 737 func setBootstrapNodesV5(ctx *cli.Context, cfg *p2p.Config) { 738 urls := params.DiscoveryV5Bootnodes 739 switch { 740 case ctx.GlobalIsSet(BootnodesFlag.Name) || ctx.GlobalIsSet(BootnodesV5Flag.Name): 741 if ctx.GlobalIsSet(BootnodesV5Flag.Name) { 742 urls = strings.Split(ctx.GlobalString(BootnodesV5Flag.Name), ",") 743 } else { 744 urls = strings.Split(ctx.GlobalString(BootnodesFlag.Name), ",") 745 } 746 case ctx.GlobalBool(RinkebyFlag.Name): 747 urls = params.RinkebyBootnodes 748 case ctx.GlobalBool(GoerliFlag.Name): 749 urls = params.GoerliBootnodes 750 case cfg.BootstrapNodesV5 != nil: 751 return // already set, don't apply defaults. 752 } 753 754 cfg.BootstrapNodesV5 = make([]*discv5.Node, 0, len(urls)) 755 for _, url := range urls { 756 node, err := discv5.ParseNode(url) 757 if err != nil { 758 log.Error("Bootstrap URL invalid", "enode", url, "err", err) 759 continue 760 } 761 cfg.BootstrapNodesV5 = append(cfg.BootstrapNodesV5, node) 762 } 763 } 764 765 // setListenAddress creates a TCP listening address string from set command 766 // line flags. 767 func setListenAddress(ctx *cli.Context, cfg *p2p.Config) { 768 if ctx.GlobalIsSet(ListenPortFlag.Name) { 769 cfg.ListenAddr = fmt.Sprintf(":%d", ctx.GlobalInt(ListenPortFlag.Name)) 770 } 771 } 772 773 // setNAT creates a port mapper from command line flags. 774 func setNAT(ctx *cli.Context, cfg *p2p.Config) { 775 if ctx.GlobalIsSet(NATFlag.Name) { 776 natif, err := nat.Parse(ctx.GlobalString(NATFlag.Name)) 777 if err != nil { 778 Fatalf("Option %s: %v", NATFlag.Name, err) 779 } 780 cfg.NAT = natif 781 } 782 } 783 784 // splitAndTrim splits input separated by a comma 785 // and trims excessive white space from the substrings. 786 func splitAndTrim(input string) []string { 787 result := strings.Split(input, ",") 788 for i, r := range result { 789 result[i] = strings.TrimSpace(r) 790 } 791 return result 792 } 793 794 // setHTTP creates the HTTP RPC listener interface string from the set 795 // command line flags, returning empty if the HTTP endpoint is disabled. 796 func setHTTP(ctx *cli.Context, cfg *node.Config) { 797 if ctx.GlobalBool(RPCEnabledFlag.Name) && cfg.HTTPHost == "" { 798 cfg.HTTPHost = "127.0.0.1" 799 if ctx.GlobalIsSet(RPCListenAddrFlag.Name) { 800 cfg.HTTPHost = ctx.GlobalString(RPCListenAddrFlag.Name) 801 } 802 } 803 804 if ctx.GlobalIsSet(RPCPortFlag.Name) { 805 cfg.HTTPPort = ctx.GlobalInt(RPCPortFlag.Name) 806 } 807 if ctx.GlobalIsSet(RPCCORSDomainFlag.Name) { 808 cfg.HTTPCors = splitAndTrim(ctx.GlobalString(RPCCORSDomainFlag.Name)) 809 } 810 if ctx.GlobalIsSet(RPCApiFlag.Name) { 811 cfg.HTTPModules = splitAndTrim(ctx.GlobalString(RPCApiFlag.Name)) 812 } 813 if ctx.GlobalIsSet(RPCVirtualHostsFlag.Name) { 814 cfg.HTTPVirtualHosts = splitAndTrim(ctx.GlobalString(RPCVirtualHostsFlag.Name)) 815 } 816 } 817 818 // setWS creates the WebSocket RPC listener interface string from the set 819 // command line flags, returning empty if the HTTP endpoint is disabled. 820 func setWS(ctx *cli.Context, cfg *node.Config) { 821 if ctx.GlobalBool(WSEnabledFlag.Name) && cfg.WSHost == "" { 822 cfg.WSHost = "127.0.0.1" 823 if ctx.GlobalIsSet(WSListenAddrFlag.Name) { 824 cfg.WSHost = ctx.GlobalString(WSListenAddrFlag.Name) 825 } 826 } 827 828 if ctx.GlobalIsSet(WSPortFlag.Name) { 829 cfg.WSPort = ctx.GlobalInt(WSPortFlag.Name) 830 } 831 if ctx.GlobalIsSet(WSAllowedOriginsFlag.Name) { 832 cfg.WSOrigins = splitAndTrim(ctx.GlobalString(WSAllowedOriginsFlag.Name)) 833 } 834 if ctx.GlobalIsSet(WSApiFlag.Name) { 835 cfg.WSModules = splitAndTrim(ctx.GlobalString(WSApiFlag.Name)) 836 } 837 } 838 839 // setIPC creates an IPC path configuration from the set command line flags, 840 // returning an empty string if IPC was explicitly disabled, or the set path. 841 func setIPC(ctx *cli.Context, cfg *node.Config) { 842 checkExclusive(ctx, IPCDisabledFlag, IPCPathFlag) 843 switch { 844 case ctx.GlobalBool(IPCDisabledFlag.Name): 845 cfg.IPCPath = "" 846 case ctx.GlobalIsSet(IPCPathFlag.Name): 847 cfg.IPCPath = ctx.GlobalString(IPCPathFlag.Name) 848 } 849 } 850 851 // makeDatabaseHandles raises out the number of allowed file handles per process 852 // for Geth and returns half of the allowance to assign to the database. 853 func makeDatabaseHandles() int { 854 limit, err := fdlimit.Maximum() 855 if err != nil { 856 Fatalf("Failed to retrieve file descriptor allowance: %v", err) 857 } 858 raised, err := fdlimit.Raise(uint64(limit)) 859 if err != nil { 860 Fatalf("Failed to raise file descriptor allowance: %v", err) 861 } 862 return int(raised / 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 setDataDir(ctx, cfg) 1004 1005 if ctx.GlobalIsSet(KeyStoreDirFlag.Name) { 1006 cfg.KeyStoreDir = ctx.GlobalString(KeyStoreDirFlag.Name) 1007 } 1008 if ctx.GlobalIsSet(LightKDFFlag.Name) { 1009 cfg.UseLightweightKDF = ctx.GlobalBool(LightKDFFlag.Name) 1010 } 1011 if ctx.GlobalIsSet(NoUSBFlag.Name) { 1012 cfg.NoUSB = ctx.GlobalBool(NoUSBFlag.Name) 1013 } 1014 } 1015 1016 func setDataDir(ctx *cli.Context, cfg *node.Config) { 1017 switch { 1018 case ctx.GlobalIsSet(DataDirFlag.Name): 1019 cfg.DataDir = ctx.GlobalString(DataDirFlag.Name) 1020 case ctx.GlobalBool(DeveloperFlag.Name): 1021 cfg.DataDir = "" // unless explicitly requested, use memory databases 1022 case ctx.GlobalBool(TestnetFlag.Name): 1023 cfg.DataDir = filepath.Join(node.DefaultDataDir(), "testnet") 1024 case ctx.GlobalBool(RinkebyFlag.Name): 1025 cfg.DataDir = filepath.Join(node.DefaultDataDir(), "rinkeby") 1026 case ctx.GlobalBool(GoerliFlag.Name): 1027 cfg.DataDir = filepath.Join(node.DefaultDataDir(), "goerli") 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 if ctx.GlobalString(PowModeFlag.Name) == quickTestPowMode { 1103 cfg.Ethash.PowMode = ethash.ModeQuickTest 1104 } else if ctx.GlobalString(PowModeFlag.Name) == cryptonightPowMode { 1105 cfg.Ethash.PowMode = ethash.ModeCryptonight 1106 } 1107 } 1108 1109 func setWhitelist(ctx *cli.Context, cfg *eth.Config) { 1110 whitelist := ctx.GlobalString(WhitelistFlag.Name) 1111 if whitelist == "" { 1112 return 1113 } 1114 cfg.Whitelist = make(map[uint64]common.Hash) 1115 for _, entry := range strings.Split(whitelist, ",") { 1116 parts := strings.Split(entry, "=") 1117 if len(parts) != 2 { 1118 Fatalf("Invalid whitelist entry: %s", entry) 1119 } 1120 number, err := strconv.ParseUint(parts[0], 0, 64) 1121 if err != nil { 1122 Fatalf("Invalid whitelist block number %s: %v", parts[0], err) 1123 } 1124 var hash common.Hash 1125 if err = hash.UnmarshalText([]byte(parts[1])); err != nil { 1126 Fatalf("Invalid whitelist hash %s: %v", parts[1], err) 1127 } 1128 cfg.Whitelist[number] = hash 1129 } 1130 } 1131 1132 // checkExclusive verifies that only a single instance of the provided flags was 1133 // set by the user. Each flag might optionally be followed by a string type to 1134 // specialize it further. 1135 func checkExclusive(ctx *cli.Context, args ...interface{}) { 1136 set := make([]string, 0, 1) 1137 for i := 0; i < len(args); i++ { 1138 // Make sure the next argument is a flag and skip if not set 1139 flag, ok := args[i].(cli.Flag) 1140 if !ok { 1141 panic(fmt.Sprintf("invalid argument, not cli.Flag type: %T", args[i])) 1142 } 1143 // Check if next arg extends current and expand its name if so 1144 name := flag.GetName() 1145 1146 if i+1 < len(args) { 1147 switch option := args[i+1].(type) { 1148 case string: 1149 // Extended flag check, make sure value set doesn't conflict with passed in option 1150 if ctx.GlobalString(flag.GetName()) == option { 1151 name += "=" + option 1152 set = append(set, "--"+name) 1153 } 1154 // shift arguments and continue 1155 i++ 1156 continue 1157 1158 case cli.Flag: 1159 default: 1160 panic(fmt.Sprintf("invalid argument, not cli.Flag or string extension: %T", args[i+1])) 1161 } 1162 } 1163 // Mark the flag if it's set 1164 if ctx.GlobalIsSet(flag.GetName()) { 1165 set = append(set, "--"+name) 1166 } 1167 } 1168 if len(set) > 1 { 1169 Fatalf("Flags %v can't be used at the same time", strings.Join(set, ", ")) 1170 } 1171 } 1172 1173 // SetShhConfig applies shh-related command line flags to the config. 1174 func SetShhConfig(ctx *cli.Context, stack *node.Node, cfg *whisper.Config) { 1175 if ctx.GlobalIsSet(WhisperMaxMessageSizeFlag.Name) { 1176 cfg.MaxMessageSize = uint32(ctx.GlobalUint(WhisperMaxMessageSizeFlag.Name)) 1177 } 1178 if ctx.GlobalIsSet(WhisperMinPOWFlag.Name) { 1179 cfg.MinimumAcceptedPOW = ctx.GlobalFloat64(WhisperMinPOWFlag.Name) 1180 } 1181 if ctx.GlobalIsSet(WhisperRestrictConnectionBetweenLightClientsFlag.Name) { 1182 cfg.RestrictConnectionBetweenLightClients = true 1183 } 1184 } 1185 1186 // SetEthConfig applies eth-related command line flags to the 1187 // config. This gets run on the main code path when starting a geth 1188 // node, for example when mining. 1189 func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) { 1190 // Avoid conflicting network flags 1191 checkExclusive(ctx, DeveloperFlag, TestnetFlag, RinkebyFlag, GoerliFlag) 1192 checkExclusive(ctx, LightServFlag, SyncModeFlag, "light") 1193 1194 ks := stack.AccountManager().Backends(keystore.KeyStoreType)[0].(*keystore.KeyStore) 1195 setEtherbase(ctx, ks, cfg) 1196 setGPO(ctx, &cfg.GPO) 1197 setTxPool(ctx, &cfg.TxPool) 1198 setEthash(ctx, cfg) 1199 setWhitelist(ctx, cfg) 1200 1201 if ctx.GlobalIsSet(SyncModeFlag.Name) { 1202 cfg.SyncMode = *GlobalTextMarshaler(ctx, SyncModeFlag.Name).(*downloader.SyncMode) 1203 } 1204 if ctx.GlobalIsSet(LightServFlag.Name) { 1205 cfg.LightServ = ctx.GlobalInt(LightServFlag.Name) 1206 } 1207 if ctx.GlobalIsSet(LightPeersFlag.Name) { 1208 cfg.LightPeers = ctx.GlobalInt(LightPeersFlag.Name) 1209 } 1210 if ctx.GlobalIsSet(NetworkIdFlag.Name) { 1211 cfg.NetworkId = ctx.GlobalUint64(NetworkIdFlag.Name) 1212 } 1213 if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheDatabaseFlag.Name) { 1214 cfg.DatabaseCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheDatabaseFlag.Name) / 100 1215 } 1216 cfg.DatabaseHandles = makeDatabaseHandles() 1217 1218 if gcmode := ctx.GlobalString(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" { 1219 Fatalf("--%s must be either 'full' or 'archive'", GCModeFlag.Name) 1220 } 1221 cfg.NoPruning = ctx.GlobalString(GCModeFlag.Name) == "archive" 1222 1223 if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheTrieFlag.Name) { 1224 cfg.TrieCleanCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheTrieFlag.Name) / 100 1225 } 1226 if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheGCFlag.Name) { 1227 cfg.TrieDirtyCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheGCFlag.Name) / 100 1228 } 1229 if ctx.GlobalIsSet(MinerNotifyFlag.Name) { 1230 cfg.MinerNotify = strings.Split(ctx.GlobalString(MinerNotifyFlag.Name), ",") 1231 } 1232 if ctx.GlobalIsSet(DocRootFlag.Name) { 1233 cfg.DocRoot = ctx.GlobalString(DocRootFlag.Name) 1234 } 1235 if ctx.GlobalIsSet(MinerLegacyExtraDataFlag.Name) { 1236 cfg.MinerExtraData = []byte(ctx.GlobalString(MinerLegacyExtraDataFlag.Name)) 1237 } 1238 if ctx.GlobalIsSet(MinerExtraDataFlag.Name) { 1239 cfg.MinerExtraData = []byte(ctx.GlobalString(MinerExtraDataFlag.Name)) 1240 } 1241 if ctx.GlobalIsSet(MinerLegacyGasTargetFlag.Name) { 1242 cfg.MinerGasFloor = ctx.GlobalUint64(MinerLegacyGasTargetFlag.Name) 1243 } 1244 if ctx.GlobalIsSet(MinerGasTargetFlag.Name) { 1245 cfg.MinerGasFloor = ctx.GlobalUint64(MinerGasTargetFlag.Name) 1246 } 1247 if ctx.GlobalIsSet(MinerGasLimitFlag.Name) { 1248 cfg.MinerGasCeil = ctx.GlobalUint64(MinerGasLimitFlag.Name) 1249 } 1250 if ctx.GlobalIsSet(MinerLegacyGasPriceFlag.Name) { 1251 cfg.MinerGasPrice = GlobalBig(ctx, MinerLegacyGasPriceFlag.Name) 1252 } 1253 if ctx.GlobalIsSet(MinerGasPriceFlag.Name) { 1254 cfg.MinerGasPrice = GlobalBig(ctx, MinerGasPriceFlag.Name) 1255 } 1256 if ctx.GlobalIsSet(MinerRecommitIntervalFlag.Name) { 1257 cfg.MinerRecommit = ctx.Duration(MinerRecommitIntervalFlag.Name) 1258 } 1259 if ctx.GlobalIsSet(MinerNoVerfiyFlag.Name) { 1260 cfg.MinerNoverify = ctx.Bool(MinerNoVerfiyFlag.Name) 1261 } 1262 if ctx.GlobalIsSet(VMEnableDebugFlag.Name) { 1263 // TODO(fjl): force-enable this in --dev mode 1264 cfg.EnablePreimageRecording = ctx.GlobalBool(VMEnableDebugFlag.Name) 1265 } 1266 1267 if ctx.GlobalIsSet(EWASMInterpreterFlag.Name) { 1268 cfg.EWASMInterpreter = ctx.GlobalString(EWASMInterpreterFlag.Name) 1269 } 1270 1271 if ctx.GlobalIsSet(EVMInterpreterFlag.Name) { 1272 cfg.EVMInterpreter = ctx.GlobalString(EVMInterpreterFlag.Name) 1273 } 1274 1275 // Override any default configs for hard coded networks. 1276 switch { 1277 case ctx.GlobalBool(TestnetFlag.Name): 1278 if !ctx.GlobalIsSet(NetworkIdFlag.Name) { 1279 cfg.NetworkId = 179109 1280 } 1281 cfg.Genesis = core.DefaultTestnetGenesisBlock() 1282 case ctx.GlobalBool(RinkebyFlag.Name): 1283 if !ctx.GlobalIsSet(NetworkIdFlag.Name) { 1284 cfg.NetworkId = 4 1285 } 1286 cfg.Genesis = core.DefaultRinkebyGenesisBlock() 1287 case ctx.GlobalBool(GoerliFlag.Name): 1288 if !ctx.GlobalIsSet(NetworkIdFlag.Name) { 1289 cfg.NetworkId = 5 1290 } 1291 cfg.Genesis = core.DefaultGoerliGenesisBlock() 1292 case ctx.GlobalBool(DeveloperFlag.Name): 1293 if !ctx.GlobalIsSet(NetworkIdFlag.Name) { 1294 cfg.NetworkId = 1337 1295 } 1296 // Create new developer account or reuse existing one 1297 var ( 1298 developer accounts.Account 1299 err error 1300 ) 1301 if accs := ks.Accounts(); len(accs) > 0 { 1302 developer = ks.Accounts()[0] 1303 } else { 1304 developer, err = ks.NewAccount("") 1305 if err != nil { 1306 Fatalf("Failed to create developer account: %v", err) 1307 } 1308 } 1309 if err := ks.Unlock(developer, ""); err != nil { 1310 Fatalf("Failed to unlock developer account: %v", err) 1311 } 1312 log.Info("Using developer account", "address", developer.Address) 1313 1314 cfg.Genesis = core.DeveloperGenesisBlock(uint64(ctx.GlobalInt(DeveloperPeriodFlag.Name)), developer.Address) 1315 if !ctx.GlobalIsSet(MinerGasPriceFlag.Name) && !ctx.GlobalIsSet(MinerLegacyGasPriceFlag.Name) { 1316 cfg.MinerGasPrice = big.NewInt(1) 1317 } 1318 } 1319 // TODO(fjl): move trie cache generations into config 1320 if gen := ctx.GlobalInt(TrieCacheGenFlag.Name); gen > 0 { 1321 state.MaxTrieCacheGen = uint16(gen) 1322 } 1323 } 1324 1325 // SetDashboardConfig applies dashboard related command line flags to the config. 1326 func SetDashboardConfig(ctx *cli.Context, cfg *dashboard.Config) { 1327 cfg.Host = ctx.GlobalString(DashboardAddrFlag.Name) 1328 cfg.Port = ctx.GlobalInt(DashboardPortFlag.Name) 1329 cfg.Refresh = ctx.GlobalDuration(DashboardRefreshFlag.Name) 1330 } 1331 1332 // RegisterEthService adds an Ethereum client to the stack. 1333 func RegisterEthService(stack *node.Node, cfg *eth.Config) { 1334 var err error 1335 if cfg.SyncMode == downloader.LightSync { 1336 err = stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { 1337 return les.New(ctx, cfg) 1338 }) 1339 } else { 1340 err = stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { 1341 fullNode, err := eth.New(ctx, cfg) 1342 if fullNode != nil && cfg.LightServ > 0 { 1343 ls, _ := les.NewLesServer(fullNode, cfg) 1344 fullNode.AddLesServer(ls) 1345 } 1346 return fullNode, err 1347 }) 1348 } 1349 if err != nil { 1350 Fatalf("Failed to register the Ethereum service: %v", err) 1351 } 1352 } 1353 1354 // RegisterDashboardService adds a dashboard to the stack. 1355 func RegisterDashboardService(stack *node.Node, cfg *dashboard.Config, commit string) { 1356 stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { 1357 return dashboard.New(cfg, commit, ctx.ResolvePath("logs")), nil 1358 }) 1359 } 1360 1361 // RegisterShhService configures Whisper and adds it to the given node. 1362 func RegisterShhService(stack *node.Node, cfg *whisper.Config) { 1363 if err := stack.Register(func(n *node.ServiceContext) (node.Service, error) { 1364 return whisper.New(cfg), nil 1365 }); err != nil { 1366 Fatalf("Failed to register the Whisper service: %v", err) 1367 } 1368 } 1369 1370 // RegisterEthStatsService configures the Ethereum Stats daemon and adds it to 1371 // the given node. 1372 func RegisterEthStatsService(stack *node.Node, url string) { 1373 if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { 1374 // Retrieve both eth and les services 1375 var ethServ *eth.Ethereum 1376 ctx.Service(ðServ) 1377 1378 var lesServ *les.LightEthereum 1379 ctx.Service(&lesServ) 1380 1381 return ethstats.New(url, ethServ, lesServ) 1382 }); err != nil { 1383 Fatalf("Failed to register the Ethereum Stats service: %v", err) 1384 } 1385 } 1386 1387 func SetupMetrics(ctx *cli.Context) { 1388 if metrics.Enabled { 1389 log.Info("Enabling metrics collection") 1390 var ( 1391 enableExport = ctx.GlobalBool(MetricsEnableInfluxDBFlag.Name) 1392 endpoint = ctx.GlobalString(MetricsInfluxDBEndpointFlag.Name) 1393 database = ctx.GlobalString(MetricsInfluxDBDatabaseFlag.Name) 1394 username = ctx.GlobalString(MetricsInfluxDBUsernameFlag.Name) 1395 password = ctx.GlobalString(MetricsInfluxDBPasswordFlag.Name) 1396 ) 1397 1398 if enableExport { 1399 tagsMap := SplitTagsFlag(ctx.GlobalString(MetricsInfluxDBTagsFlag.Name)) 1400 1401 log.Info("Enabling metrics export to InfluxDB") 1402 1403 go influxdb.InfluxDBWithTags(metrics.DefaultRegistry, 10*time.Second, endpoint, database, username, password, "geth.", tagsMap) 1404 } 1405 } 1406 } 1407 1408 func SplitTagsFlag(tagsFlag string) map[string]string { 1409 tags := strings.Split(tagsFlag, ",") 1410 tagsMap := map[string]string{} 1411 1412 for _, t := range tags { 1413 if t != "" { 1414 kv := strings.Split(t, "=") 1415 1416 if len(kv) == 2 { 1417 tagsMap[kv[0]] = kv[1] 1418 } 1419 } 1420 } 1421 1422 return tagsMap 1423 } 1424 1425 // MakeChainDatabase open an LevelDB using the flags passed to the client and will hard crash if it fails. 1426 func MakeChainDatabase(ctx *cli.Context, stack *node.Node) ethdb.Database { 1427 var ( 1428 cache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheDatabaseFlag.Name) / 100 1429 handles = makeDatabaseHandles() 1430 ) 1431 name := "chaindata" 1432 if ctx.GlobalString(SyncModeFlag.Name) == "light" { 1433 name = "lightchaindata" 1434 } 1435 chainDb, err := stack.OpenDatabase(name, cache, handles) 1436 if err != nil { 1437 Fatalf("Could not open database: %v", err) 1438 } 1439 return chainDb 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(GoerliFlag.Name): 1450 genesis = core.DefaultGoerliGenesisBlock() 1451 case ctx.GlobalBool(DeveloperFlag.Name): 1452 Fatalf("Developer chains are ephemeral") 1453 } 1454 return genesis 1455 } 1456 1457 1458 // MakeChain creates a chain manager from set command line flags. This 1459 // doesn't get run on the main geth code path (e.g. when mining). It's 1460 // only used by auxiliary commands like import, export, or copydb. 1461 func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chainDb ethdb.Database) { 1462 var err error 1463 chainDb = MakeChainDatabase(ctx, stack) 1464 config, _, err := core.SetupGenesisBlock(chainDb, MakeGenesis(ctx)) 1465 if err != nil { 1466 Fatalf("%v", err) 1467 } 1468 var engine consensus.Engine 1469 if config.Clique != nil { 1470 engine = clique.New(config.Clique, chainDb) 1471 } else if ctx.GlobalBool(FakePoWFlag.Name) { 1472 engine = ethash.NewFaker() 1473 } else if ctx.GlobalString(PowModeFlag.Name) == quickTestPowMode { 1474 engine = ethash.NewQuickTest(nil, false) 1475 } else if ctx.GlobalString(PowModeFlag.Name) == cryptonightPowMode { 1476 engine = ethash.NewCryptonight(nil, false) 1477 } else if ctx.GlobalString(PowModeFlag.Name) == ethashPowMode { 1478 engine = ethash.New(ethash.Config{ 1479 CacheDir: stack.ResolvePath(eth.DefaultConfig.Ethash.CacheDir), 1480 CachesInMem: eth.DefaultConfig.Ethash.CachesInMem, 1481 CachesOnDisk: eth.DefaultConfig.Ethash.CachesOnDisk, 1482 DatasetDir: stack.ResolvePath(eth.DefaultConfig.Ethash.DatasetDir), 1483 DatasetsInMem: eth.DefaultConfig.Ethash.DatasetsInMem, 1484 DatasetsOnDisk: eth.DefaultConfig.Ethash.DatasetsOnDisk, 1485 }, nil, false) 1486 } else { 1487 Fatalf("Invalid pow mode flag value: %s", ctx.GlobalString(PowModeFlag.Name)) 1488 } 1489 if gcmode := ctx.GlobalString(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" { 1490 Fatalf("--%s must be either 'full' or 'archive'", GCModeFlag.Name) 1491 } 1492 cache := &core.CacheConfig{ 1493 Disabled: ctx.GlobalString(GCModeFlag.Name) == "archive", 1494 TrieCleanLimit: eth.DefaultConfig.TrieCleanCache, 1495 TrieDirtyLimit: eth.DefaultConfig.TrieDirtyCache, 1496 TrieTimeLimit: eth.DefaultConfig.TrieTimeout, 1497 } 1498 if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheTrieFlag.Name) { 1499 cache.TrieCleanLimit = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheTrieFlag.Name) / 100 1500 } 1501 if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheGCFlag.Name) { 1502 cache.TrieDirtyLimit = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheGCFlag.Name) / 100 1503 } 1504 vmcfg := vm.Config{EnablePreimageRecording: ctx.GlobalBool(VMEnableDebugFlag.Name)} 1505 chain, err = core.NewBlockChain(chainDb, cache, config, engine, vmcfg, nil) 1506 if err != nil { 1507 Fatalf("Can't create BlockChain: %v", err) 1508 } 1509 return chain, chainDb 1510 } 1511 1512 // MakeConsolePreloads retrieves the absolute paths for the console JavaScript 1513 // scripts to preload before starting. 1514 func MakeConsolePreloads(ctx *cli.Context) []string { 1515 // Skip preloading if there's nothing to preload 1516 if ctx.GlobalString(PreloadJSFlag.Name) == "" { 1517 return nil 1518 } 1519 // Otherwise resolve absolute paths and return them 1520 preloads := []string{} 1521 1522 assets := ctx.GlobalString(JSpathFlag.Name) 1523 for _, file := range strings.Split(ctx.GlobalString(PreloadJSFlag.Name), ",") { 1524 preloads = append(preloads, common.AbsolutePath(assets, strings.TrimSpace(file))) 1525 } 1526 return preloads 1527 } 1528 1529 // MigrateFlags sets the global flag from a local flag when it's set. 1530 // This is a temporary function used for migrating old command/flags to the 1531 // new format. 1532 // 1533 // e.g. geth account new --keystore /tmp/mykeystore --lightkdf 1534 // 1535 // is equivalent after calling this method with: 1536 // 1537 // geth --keystore /tmp/mykeystore --lightkdf account new 1538 // 1539 // This allows the use of the existing configuration functionality. 1540 // When all flags are migrated this function can be removed and the existing 1541 // configuration functionality must be changed that is uses local flags 1542 func MigrateFlags(action func(ctx *cli.Context) error) func(*cli.Context) error { 1543 return func(ctx *cli.Context) error { 1544 for _, name := range ctx.FlagNames() { 1545 if ctx.IsSet(name) { 1546 ctx.GlobalSet(name, ctx.String(name)) 1547 } 1548 } 1549 return action(ctx) 1550 } 1551 }