github.com/ethereum/go-ethereum@v1.10.9/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" 24 "io/ioutil" 25 "math" 26 "math/big" 27 "os" 28 "path/filepath" 29 godebug "runtime/debug" 30 "strconv" 31 "strings" 32 "text/tabwriter" 33 "text/template" 34 "time" 35 36 "github.com/ethereum/go-ethereum/accounts" 37 "github.com/ethereum/go-ethereum/accounts/keystore" 38 "github.com/ethereum/go-ethereum/common" 39 "github.com/ethereum/go-ethereum/common/fdlimit" 40 "github.com/ethereum/go-ethereum/consensus" 41 "github.com/ethereum/go-ethereum/consensus/clique" 42 "github.com/ethereum/go-ethereum/consensus/ethash" 43 "github.com/ethereum/go-ethereum/core" 44 "github.com/ethereum/go-ethereum/core/rawdb" 45 "github.com/ethereum/go-ethereum/core/vm" 46 "github.com/ethereum/go-ethereum/crypto" 47 "github.com/ethereum/go-ethereum/eth" 48 "github.com/ethereum/go-ethereum/eth/downloader" 49 "github.com/ethereum/go-ethereum/eth/ethconfig" 50 "github.com/ethereum/go-ethereum/eth/gasprice" 51 "github.com/ethereum/go-ethereum/eth/tracers" 52 "github.com/ethereum/go-ethereum/ethdb" 53 "github.com/ethereum/go-ethereum/ethstats" 54 "github.com/ethereum/go-ethereum/graphql" 55 "github.com/ethereum/go-ethereum/internal/ethapi" 56 "github.com/ethereum/go-ethereum/internal/flags" 57 "github.com/ethereum/go-ethereum/les" 58 "github.com/ethereum/go-ethereum/log" 59 "github.com/ethereum/go-ethereum/metrics" 60 "github.com/ethereum/go-ethereum/metrics/exp" 61 "github.com/ethereum/go-ethereum/metrics/influxdb" 62 "github.com/ethereum/go-ethereum/miner" 63 "github.com/ethereum/go-ethereum/node" 64 "github.com/ethereum/go-ethereum/p2p" 65 "github.com/ethereum/go-ethereum/p2p/enode" 66 "github.com/ethereum/go-ethereum/p2p/nat" 67 "github.com/ethereum/go-ethereum/p2p/netutil" 68 "github.com/ethereum/go-ethereum/params" 69 pcsclite "github.com/gballet/go-libpcsclite" 70 gopsutil "github.com/shirou/gopsutil/mem" 71 "gopkg.in/urfave/cli.v1" 72 ) 73 74 func init() { 75 cli.AppHelpTemplate = `{{.Name}} {{if .Flags}}[global options] {{end}}command{{if .Flags}} [command options]{{end}} [arguments...] 76 77 VERSION: 78 {{.Version}} 79 80 COMMANDS: 81 {{range .Commands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}} 82 {{end}}{{if .Flags}} 83 GLOBAL OPTIONS: 84 {{range .Flags}}{{.}} 85 {{end}}{{end}} 86 ` 87 cli.CommandHelpTemplate = flags.CommandHelpTemplate 88 cli.HelpPrinter = printHelp 89 } 90 91 func printHelp(out io.Writer, templ string, data interface{}) { 92 funcMap := template.FuncMap{"join": strings.Join} 93 t := template.Must(template.New("help").Funcs(funcMap).Parse(templ)) 94 w := tabwriter.NewWriter(out, 38, 8, 2, ' ', 0) 95 err := t.Execute(w, data) 96 if err != nil { 97 panic(err) 98 } 99 w.Flush() 100 } 101 102 // These are all the command line flags we support. 103 // If you add to this list, please remember to include the 104 // flag in the appropriate command definition. 105 // 106 // The flags are defined here so their names and help texts 107 // are the same for all commands. 108 109 var ( 110 // General settings 111 DataDirFlag = DirectoryFlag{ 112 Name: "datadir", 113 Usage: "Data directory for the databases and keystore", 114 Value: DirectoryString(node.DefaultDataDir()), 115 } 116 AncientFlag = DirectoryFlag{ 117 Name: "datadir.ancient", 118 Usage: "Data directory for ancient chain segments (default = inside chaindata)", 119 } 120 MinFreeDiskSpaceFlag = DirectoryFlag{ 121 Name: "datadir.minfreedisk", 122 Usage: "Minimum free disk space in MB, once reached triggers auto shut down (default = --cache.gc converted to MB, 0 = disabled)", 123 } 124 KeyStoreDirFlag = DirectoryFlag{ 125 Name: "keystore", 126 Usage: "Directory for the keystore (default = inside the datadir)", 127 } 128 USBFlag = cli.BoolFlag{ 129 Name: "usb", 130 Usage: "Enable monitoring and management of USB hardware wallets", 131 } 132 SmartCardDaemonPathFlag = cli.StringFlag{ 133 Name: "pcscdpath", 134 Usage: "Path to the smartcard daemon (pcscd) socket file", 135 Value: pcsclite.PCSCDSockName, 136 } 137 NetworkIdFlag = cli.Uint64Flag{ 138 Name: "networkid", 139 Usage: "Explicitly set network id (integer)(For testnets: use --ropsten, --rinkeby, --goerli instead)", 140 Value: ethconfig.Defaults.NetworkId, 141 } 142 MainnetFlag = cli.BoolFlag{ 143 Name: "mainnet", 144 Usage: "Ethereum mainnet", 145 } 146 GoerliFlag = cli.BoolFlag{ 147 Name: "goerli", 148 Usage: "Görli network: pre-configured proof-of-authority test network", 149 } 150 RinkebyFlag = cli.BoolFlag{ 151 Name: "rinkeby", 152 Usage: "Rinkeby network: pre-configured proof-of-authority test network", 153 } 154 RopstenFlag = cli.BoolFlag{ 155 Name: "ropsten", 156 Usage: "Ropsten network: pre-configured proof-of-work test network", 157 } 158 DeveloperFlag = cli.BoolFlag{ 159 Name: "dev", 160 Usage: "Ephemeral proof-of-authority network with a pre-funded developer account, mining enabled", 161 } 162 DeveloperPeriodFlag = cli.IntFlag{ 163 Name: "dev.period", 164 Usage: "Block period to use in developer mode (0 = mine only if transaction pending)", 165 } 166 IdentityFlag = cli.StringFlag{ 167 Name: "identity", 168 Usage: "Custom node name", 169 } 170 DocRootFlag = DirectoryFlag{ 171 Name: "docroot", 172 Usage: "Document Root for HTTPClient file scheme", 173 Value: DirectoryString(HomeDir()), 174 } 175 ExitWhenSyncedFlag = cli.BoolFlag{ 176 Name: "exitwhensynced", 177 Usage: "Exits after block synchronisation completes", 178 } 179 IterativeOutputFlag = cli.BoolTFlag{ 180 Name: "iterative", 181 Usage: "Print streaming JSON iteratively, delimited by newlines", 182 } 183 ExcludeStorageFlag = cli.BoolFlag{ 184 Name: "nostorage", 185 Usage: "Exclude storage entries (save db lookups)", 186 } 187 IncludeIncompletesFlag = cli.BoolFlag{ 188 Name: "incompletes", 189 Usage: "Include accounts for which we don't have the address (missing preimage)", 190 } 191 ExcludeCodeFlag = cli.BoolFlag{ 192 Name: "nocode", 193 Usage: "Exclude contract code (save db lookups)", 194 } 195 StartKeyFlag = cli.StringFlag{ 196 Name: "start", 197 Usage: "Start position. Either a hash or address", 198 Value: "0x0000000000000000000000000000000000000000000000000000000000000000", 199 } 200 DumpLimitFlag = cli.Uint64Flag{ 201 Name: "limit", 202 Usage: "Max number of elements (0 = no limit)", 203 Value: 0, 204 } 205 defaultSyncMode = ethconfig.Defaults.SyncMode 206 SyncModeFlag = TextMarshalerFlag{ 207 Name: "syncmode", 208 Usage: `Blockchain sync mode ("fast", "full", "snap" or "light")`, 209 Value: &defaultSyncMode, 210 } 211 GCModeFlag = cli.StringFlag{ 212 Name: "gcmode", 213 Usage: `Blockchain garbage collection mode ("full", "archive")`, 214 Value: "full", 215 } 216 SnapshotFlag = cli.BoolTFlag{ 217 Name: "snapshot", 218 Usage: `Enables snapshot-database mode (default = enable)`, 219 } 220 TxLookupLimitFlag = cli.Uint64Flag{ 221 Name: "txlookuplimit", 222 Usage: "Number of recent blocks to maintain transactions index for (default = about one year, 0 = entire chain)", 223 Value: ethconfig.Defaults.TxLookupLimit, 224 } 225 LightKDFFlag = cli.BoolFlag{ 226 Name: "lightkdf", 227 Usage: "Reduce key-derivation RAM & CPU usage at some expense of KDF strength", 228 } 229 WhitelistFlag = cli.StringFlag{ 230 Name: "whitelist", 231 Usage: "Comma separated block number-to-hash mappings to enforce (<number>=<hash>)", 232 } 233 BloomFilterSizeFlag = cli.Uint64Flag{ 234 Name: "bloomfilter.size", 235 Usage: "Megabytes of memory allocated to bloom-filter for pruning", 236 Value: 2048, 237 } 238 OverrideLondonFlag = cli.Uint64Flag{ 239 Name: "override.london", 240 Usage: "Manually specify London fork-block, overriding the bundled setting", 241 } 242 // Light server and client settings 243 LightServeFlag = cli.IntFlag{ 244 Name: "light.serve", 245 Usage: "Maximum percentage of time allowed for serving LES requests (multi-threaded processing allows values over 100)", 246 Value: ethconfig.Defaults.LightServ, 247 } 248 LightIngressFlag = cli.IntFlag{ 249 Name: "light.ingress", 250 Usage: "Incoming bandwidth limit for serving light clients (kilobytes/sec, 0 = unlimited)", 251 Value: ethconfig.Defaults.LightIngress, 252 } 253 LightEgressFlag = cli.IntFlag{ 254 Name: "light.egress", 255 Usage: "Outgoing bandwidth limit for serving light clients (kilobytes/sec, 0 = unlimited)", 256 Value: ethconfig.Defaults.LightEgress, 257 } 258 LightMaxPeersFlag = cli.IntFlag{ 259 Name: "light.maxpeers", 260 Usage: "Maximum number of light clients to serve, or light servers to attach to", 261 Value: ethconfig.Defaults.LightPeers, 262 } 263 UltraLightServersFlag = cli.StringFlag{ 264 Name: "ulc.servers", 265 Usage: "List of trusted ultra-light servers", 266 Value: strings.Join(ethconfig.Defaults.UltraLightServers, ","), 267 } 268 UltraLightFractionFlag = cli.IntFlag{ 269 Name: "ulc.fraction", 270 Usage: "Minimum % of trusted ultra-light servers required to announce a new head", 271 Value: ethconfig.Defaults.UltraLightFraction, 272 } 273 UltraLightOnlyAnnounceFlag = cli.BoolFlag{ 274 Name: "ulc.onlyannounce", 275 Usage: "Ultra light server sends announcements only", 276 } 277 LightNoPruneFlag = cli.BoolFlag{ 278 Name: "light.nopruning", 279 Usage: "Disable ancient light chain data pruning", 280 } 281 LightNoSyncServeFlag = cli.BoolFlag{ 282 Name: "light.nosyncserve", 283 Usage: "Enables serving light clients before syncing", 284 } 285 // Ethash settings 286 EthashCacheDirFlag = DirectoryFlag{ 287 Name: "ethash.cachedir", 288 Usage: "Directory to store the ethash verification caches (default = inside the datadir)", 289 } 290 EthashCachesInMemoryFlag = cli.IntFlag{ 291 Name: "ethash.cachesinmem", 292 Usage: "Number of recent ethash caches to keep in memory (16MB each)", 293 Value: ethconfig.Defaults.Ethash.CachesInMem, 294 } 295 EthashCachesOnDiskFlag = cli.IntFlag{ 296 Name: "ethash.cachesondisk", 297 Usage: "Number of recent ethash caches to keep on disk (16MB each)", 298 Value: ethconfig.Defaults.Ethash.CachesOnDisk, 299 } 300 EthashCachesLockMmapFlag = cli.BoolFlag{ 301 Name: "ethash.cacheslockmmap", 302 Usage: "Lock memory maps of recent ethash caches", 303 } 304 EthashDatasetDirFlag = DirectoryFlag{ 305 Name: "ethash.dagdir", 306 Usage: "Directory to store the ethash mining DAGs", 307 Value: DirectoryString(ethconfig.Defaults.Ethash.DatasetDir), 308 } 309 EthashDatasetsInMemoryFlag = cli.IntFlag{ 310 Name: "ethash.dagsinmem", 311 Usage: "Number of recent ethash mining DAGs to keep in memory (1+GB each)", 312 Value: ethconfig.Defaults.Ethash.DatasetsInMem, 313 } 314 EthashDatasetsOnDiskFlag = cli.IntFlag{ 315 Name: "ethash.dagsondisk", 316 Usage: "Number of recent ethash mining DAGs to keep on disk (1+GB each)", 317 Value: ethconfig.Defaults.Ethash.DatasetsOnDisk, 318 } 319 EthashDatasetsLockMmapFlag = cli.BoolFlag{ 320 Name: "ethash.dagslockmmap", 321 Usage: "Lock memory maps for recent ethash mining DAGs", 322 } 323 // Transaction pool settings 324 TxPoolLocalsFlag = cli.StringFlag{ 325 Name: "txpool.locals", 326 Usage: "Comma separated accounts to treat as locals (no flush, priority inclusion)", 327 } 328 TxPoolNoLocalsFlag = cli.BoolFlag{ 329 Name: "txpool.nolocals", 330 Usage: "Disables price exemptions for locally submitted transactions", 331 } 332 TxPoolJournalFlag = cli.StringFlag{ 333 Name: "txpool.journal", 334 Usage: "Disk journal for local transaction to survive node restarts", 335 Value: core.DefaultTxPoolConfig.Journal, 336 } 337 TxPoolRejournalFlag = cli.DurationFlag{ 338 Name: "txpool.rejournal", 339 Usage: "Time interval to regenerate the local transaction journal", 340 Value: core.DefaultTxPoolConfig.Rejournal, 341 } 342 TxPoolPriceLimitFlag = cli.Uint64Flag{ 343 Name: "txpool.pricelimit", 344 Usage: "Minimum gas price limit to enforce for acceptance into the pool", 345 Value: ethconfig.Defaults.TxPool.PriceLimit, 346 } 347 TxPoolPriceBumpFlag = cli.Uint64Flag{ 348 Name: "txpool.pricebump", 349 Usage: "Price bump percentage to replace an already existing transaction", 350 Value: ethconfig.Defaults.TxPool.PriceBump, 351 } 352 TxPoolAccountSlotsFlag = cli.Uint64Flag{ 353 Name: "txpool.accountslots", 354 Usage: "Minimum number of executable transaction slots guaranteed per account", 355 Value: ethconfig.Defaults.TxPool.AccountSlots, 356 } 357 TxPoolGlobalSlotsFlag = cli.Uint64Flag{ 358 Name: "txpool.globalslots", 359 Usage: "Maximum number of executable transaction slots for all accounts", 360 Value: ethconfig.Defaults.TxPool.GlobalSlots, 361 } 362 TxPoolAccountQueueFlag = cli.Uint64Flag{ 363 Name: "txpool.accountqueue", 364 Usage: "Maximum number of non-executable transaction slots permitted per account", 365 Value: ethconfig.Defaults.TxPool.AccountQueue, 366 } 367 TxPoolGlobalQueueFlag = cli.Uint64Flag{ 368 Name: "txpool.globalqueue", 369 Usage: "Maximum number of non-executable transaction slots for all accounts", 370 Value: ethconfig.Defaults.TxPool.GlobalQueue, 371 } 372 TxPoolLifetimeFlag = cli.DurationFlag{ 373 Name: "txpool.lifetime", 374 Usage: "Maximum amount of time non-executable transaction are queued", 375 Value: ethconfig.Defaults.TxPool.Lifetime, 376 } 377 // Performance tuning settings 378 CacheFlag = cli.IntFlag{ 379 Name: "cache", 380 Usage: "Megabytes of memory allocated to internal caching (default = 4096 mainnet full node, 128 light mode)", 381 Value: 1024, 382 } 383 CacheDatabaseFlag = cli.IntFlag{ 384 Name: "cache.database", 385 Usage: "Percentage of cache memory allowance to use for database io", 386 Value: 50, 387 } 388 CacheTrieFlag = cli.IntFlag{ 389 Name: "cache.trie", 390 Usage: "Percentage of cache memory allowance to use for trie caching (default = 15% full mode, 30% archive mode)", 391 Value: 15, 392 } 393 CacheTrieJournalFlag = cli.StringFlag{ 394 Name: "cache.trie.journal", 395 Usage: "Disk journal directory for trie cache to survive node restarts", 396 Value: ethconfig.Defaults.TrieCleanCacheJournal, 397 } 398 CacheTrieRejournalFlag = cli.DurationFlag{ 399 Name: "cache.trie.rejournal", 400 Usage: "Time interval to regenerate the trie cache journal", 401 Value: ethconfig.Defaults.TrieCleanCacheRejournal, 402 } 403 CacheGCFlag = cli.IntFlag{ 404 Name: "cache.gc", 405 Usage: "Percentage of cache memory allowance to use for trie pruning (default = 25% full mode, 0% archive mode)", 406 Value: 25, 407 } 408 CacheSnapshotFlag = cli.IntFlag{ 409 Name: "cache.snapshot", 410 Usage: "Percentage of cache memory allowance to use for snapshot caching (default = 10% full mode, 20% archive mode)", 411 Value: 10, 412 } 413 CacheNoPrefetchFlag = cli.BoolFlag{ 414 Name: "cache.noprefetch", 415 Usage: "Disable heuristic state prefetch during block import (less CPU and disk IO, more time waiting for data)", 416 } 417 CachePreimagesFlag = cli.BoolFlag{ 418 Name: "cache.preimages", 419 Usage: "Enable recording the SHA3/keccak preimages of trie keys", 420 } 421 // Miner settings 422 MiningEnabledFlag = cli.BoolFlag{ 423 Name: "mine", 424 Usage: "Enable mining", 425 } 426 MinerThreadsFlag = cli.IntFlag{ 427 Name: "miner.threads", 428 Usage: "Number of CPU threads to use for mining", 429 Value: 0, 430 } 431 MinerNotifyFlag = cli.StringFlag{ 432 Name: "miner.notify", 433 Usage: "Comma separated HTTP URL list to notify of new work packages", 434 } 435 MinerNotifyFullFlag = cli.BoolFlag{ 436 Name: "miner.notify.full", 437 Usage: "Notify with pending block headers instead of work packages", 438 } 439 MinerGasLimitFlag = cli.Uint64Flag{ 440 Name: "miner.gaslimit", 441 Usage: "Target gas ceiling for mined blocks", 442 Value: ethconfig.Defaults.Miner.GasCeil, 443 } 444 MinerGasPriceFlag = BigFlag{ 445 Name: "miner.gasprice", 446 Usage: "Minimum gas price for mining a transaction", 447 Value: ethconfig.Defaults.Miner.GasPrice, 448 } 449 MinerEtherbaseFlag = cli.StringFlag{ 450 Name: "miner.etherbase", 451 Usage: "Public address for block mining rewards (default = first account)", 452 Value: "0", 453 } 454 MinerExtraDataFlag = cli.StringFlag{ 455 Name: "miner.extradata", 456 Usage: "Block extra data set by the miner (default = client version)", 457 } 458 MinerRecommitIntervalFlag = cli.DurationFlag{ 459 Name: "miner.recommit", 460 Usage: "Time interval to recreate the block being mined", 461 Value: ethconfig.Defaults.Miner.Recommit, 462 } 463 MinerNoVerifyFlag = cli.BoolFlag{ 464 Name: "miner.noverify", 465 Usage: "Disable remote sealing verification", 466 } 467 // Account settings 468 UnlockedAccountFlag = cli.StringFlag{ 469 Name: "unlock", 470 Usage: "Comma separated list of accounts to unlock", 471 Value: "", 472 } 473 PasswordFileFlag = cli.StringFlag{ 474 Name: "password", 475 Usage: "Password file to use for non-interactive password input", 476 Value: "", 477 } 478 ExternalSignerFlag = cli.StringFlag{ 479 Name: "signer", 480 Usage: "External signer (url or path to ipc file)", 481 Value: "", 482 } 483 VMEnableDebugFlag = cli.BoolFlag{ 484 Name: "vmdebug", 485 Usage: "Record information useful for VM and contract debugging", 486 } 487 InsecureUnlockAllowedFlag = cli.BoolFlag{ 488 Name: "allow-insecure-unlock", 489 Usage: "Allow insecure account unlocking when account-related RPCs are exposed by http", 490 } 491 RPCGlobalGasCapFlag = cli.Uint64Flag{ 492 Name: "rpc.gascap", 493 Usage: "Sets a cap on gas that can be used in eth_call/estimateGas (0=infinite)", 494 Value: ethconfig.Defaults.RPCGasCap, 495 } 496 RPCGlobalTxFeeCapFlag = cli.Float64Flag{ 497 Name: "rpc.txfeecap", 498 Usage: "Sets a cap on transaction fee (in ether) that can be sent via the RPC APIs (0 = no cap)", 499 Value: ethconfig.Defaults.RPCTxFeeCap, 500 } 501 // Logging and debug settings 502 EthStatsURLFlag = cli.StringFlag{ 503 Name: "ethstats", 504 Usage: "Reporting URL of a ethstats service (nodename:secret@host:port)", 505 } 506 FakePoWFlag = cli.BoolFlag{ 507 Name: "fakepow", 508 Usage: "Disables proof-of-work verification", 509 } 510 NoCompactionFlag = cli.BoolFlag{ 511 Name: "nocompaction", 512 Usage: "Disables db compaction after import", 513 } 514 // RPC settings 515 IPCDisabledFlag = cli.BoolFlag{ 516 Name: "ipcdisable", 517 Usage: "Disable the IPC-RPC server", 518 } 519 IPCPathFlag = DirectoryFlag{ 520 Name: "ipcpath", 521 Usage: "Filename for IPC socket/pipe within the datadir (explicit paths escape it)", 522 } 523 HTTPEnabledFlag = cli.BoolFlag{ 524 Name: "http", 525 Usage: "Enable the HTTP-RPC server", 526 } 527 HTTPListenAddrFlag = cli.StringFlag{ 528 Name: "http.addr", 529 Usage: "HTTP-RPC server listening interface", 530 Value: node.DefaultHTTPHost, 531 } 532 HTTPPortFlag = cli.IntFlag{ 533 Name: "http.port", 534 Usage: "HTTP-RPC server listening port", 535 Value: node.DefaultHTTPPort, 536 } 537 HTTPCORSDomainFlag = cli.StringFlag{ 538 Name: "http.corsdomain", 539 Usage: "Comma separated list of domains from which to accept cross origin requests (browser enforced)", 540 Value: "", 541 } 542 HTTPVirtualHostsFlag = cli.StringFlag{ 543 Name: "http.vhosts", 544 Usage: "Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard.", 545 Value: strings.Join(node.DefaultConfig.HTTPVirtualHosts, ","), 546 } 547 HTTPApiFlag = cli.StringFlag{ 548 Name: "http.api", 549 Usage: "API's offered over the HTTP-RPC interface", 550 Value: "", 551 } 552 HTTPPathPrefixFlag = cli.StringFlag{ 553 Name: "http.rpcprefix", 554 Usage: "HTTP path path prefix on which JSON-RPC is served. Use '/' to serve on all paths.", 555 Value: "", 556 } 557 GraphQLEnabledFlag = cli.BoolFlag{ 558 Name: "graphql", 559 Usage: "Enable GraphQL on the HTTP-RPC server. Note that GraphQL can only be started if an HTTP server is started as well.", 560 } 561 GraphQLCORSDomainFlag = cli.StringFlag{ 562 Name: "graphql.corsdomain", 563 Usage: "Comma separated list of domains from which to accept cross origin requests (browser enforced)", 564 Value: "", 565 } 566 GraphQLVirtualHostsFlag = cli.StringFlag{ 567 Name: "graphql.vhosts", 568 Usage: "Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard.", 569 Value: strings.Join(node.DefaultConfig.GraphQLVirtualHosts, ","), 570 } 571 WSEnabledFlag = cli.BoolFlag{ 572 Name: "ws", 573 Usage: "Enable the WS-RPC server", 574 } 575 WSListenAddrFlag = cli.StringFlag{ 576 Name: "ws.addr", 577 Usage: "WS-RPC server listening interface", 578 Value: node.DefaultWSHost, 579 } 580 WSPortFlag = cli.IntFlag{ 581 Name: "ws.port", 582 Usage: "WS-RPC server listening port", 583 Value: node.DefaultWSPort, 584 } 585 WSApiFlag = cli.StringFlag{ 586 Name: "ws.api", 587 Usage: "API's offered over the WS-RPC interface", 588 Value: "", 589 } 590 WSAllowedOriginsFlag = cli.StringFlag{ 591 Name: "ws.origins", 592 Usage: "Origins from which to accept websockets requests", 593 Value: "", 594 } 595 WSPathPrefixFlag = cli.StringFlag{ 596 Name: "ws.rpcprefix", 597 Usage: "HTTP path prefix on which JSON-RPC is served. Use '/' to serve on all paths.", 598 Value: "", 599 } 600 ExecFlag = cli.StringFlag{ 601 Name: "exec", 602 Usage: "Execute JavaScript statement", 603 } 604 PreloadJSFlag = cli.StringFlag{ 605 Name: "preload", 606 Usage: "Comma separated list of JavaScript files to preload into the console", 607 } 608 AllowUnprotectedTxs = cli.BoolFlag{ 609 Name: "rpc.allow-unprotected-txs", 610 Usage: "Allow for unprotected (non EIP155 signed) transactions to be submitted via RPC", 611 } 612 613 // Network Settings 614 MaxPeersFlag = cli.IntFlag{ 615 Name: "maxpeers", 616 Usage: "Maximum number of network peers (network disabled if set to 0)", 617 Value: node.DefaultConfig.P2P.MaxPeers, 618 } 619 MaxPendingPeersFlag = cli.IntFlag{ 620 Name: "maxpendpeers", 621 Usage: "Maximum number of pending connection attempts (defaults used if set to 0)", 622 Value: node.DefaultConfig.P2P.MaxPendingPeers, 623 } 624 ListenPortFlag = cli.IntFlag{ 625 Name: "port", 626 Usage: "Network listening port", 627 Value: 30303, 628 } 629 BootnodesFlag = cli.StringFlag{ 630 Name: "bootnodes", 631 Usage: "Comma separated enode URLs for P2P discovery bootstrap", 632 Value: "", 633 } 634 NodeKeyFileFlag = cli.StringFlag{ 635 Name: "nodekey", 636 Usage: "P2P node key file", 637 } 638 NodeKeyHexFlag = cli.StringFlag{ 639 Name: "nodekeyhex", 640 Usage: "P2P node key as hex (for testing)", 641 } 642 NATFlag = cli.StringFlag{ 643 Name: "nat", 644 Usage: "NAT port mapping mechanism (any|none|upnp|pmp|extip:<IP>)", 645 Value: "any", 646 } 647 NoDiscoverFlag = cli.BoolFlag{ 648 Name: "nodiscover", 649 Usage: "Disables the peer discovery mechanism (manual peer addition)", 650 } 651 DiscoveryV5Flag = cli.BoolFlag{ 652 Name: "v5disc", 653 Usage: "Enables the experimental RLPx V5 (Topic Discovery) mechanism", 654 } 655 NetrestrictFlag = cli.StringFlag{ 656 Name: "netrestrict", 657 Usage: "Restricts network communication to the given IP networks (CIDR masks)", 658 } 659 DNSDiscoveryFlag = cli.StringFlag{ 660 Name: "discovery.dns", 661 Usage: "Sets DNS discovery entry points (use \"\" to disable DNS)", 662 } 663 664 // ATM the url is left to the user and deployment to 665 JSpathFlag = DirectoryFlag{ 666 Name: "jspath", 667 Usage: "JavaScript root path for `loadScript`", 668 Value: DirectoryString("."), 669 } 670 671 // Gas price oracle settings 672 GpoBlocksFlag = cli.IntFlag{ 673 Name: "gpo.blocks", 674 Usage: "Number of recent blocks to check for gas prices", 675 Value: ethconfig.Defaults.GPO.Blocks, 676 } 677 GpoPercentileFlag = cli.IntFlag{ 678 Name: "gpo.percentile", 679 Usage: "Suggested gas price is the given percentile of a set of recent transaction gas prices", 680 Value: ethconfig.Defaults.GPO.Percentile, 681 } 682 GpoMaxGasPriceFlag = cli.Int64Flag{ 683 Name: "gpo.maxprice", 684 Usage: "Maximum gas price will be recommended by gpo", 685 Value: ethconfig.Defaults.GPO.MaxPrice.Int64(), 686 } 687 GpoIgnoreGasPriceFlag = cli.Int64Flag{ 688 Name: "gpo.ignoreprice", 689 Usage: "Gas price below which gpo will ignore transactions", 690 Value: ethconfig.Defaults.GPO.IgnorePrice.Int64(), 691 } 692 693 // Metrics flags 694 MetricsEnabledFlag = cli.BoolFlag{ 695 Name: "metrics", 696 Usage: "Enable metrics collection and reporting", 697 } 698 MetricsEnabledExpensiveFlag = cli.BoolFlag{ 699 Name: "metrics.expensive", 700 Usage: "Enable expensive metrics collection and reporting", 701 } 702 703 // MetricsHTTPFlag defines the endpoint for a stand-alone metrics HTTP endpoint. 704 // Since the pprof service enables sensitive/vulnerable behavior, this allows a user 705 // to enable a public-OK metrics endpoint without having to worry about ALSO exposing 706 // other profiling behavior or information. 707 MetricsHTTPFlag = cli.StringFlag{ 708 Name: "metrics.addr", 709 Usage: "Enable stand-alone metrics HTTP server listening interface", 710 Value: metrics.DefaultConfig.HTTP, 711 } 712 MetricsPortFlag = cli.IntFlag{ 713 Name: "metrics.port", 714 Usage: "Metrics HTTP server listening port", 715 Value: metrics.DefaultConfig.Port, 716 } 717 MetricsEnableInfluxDBFlag = cli.BoolFlag{ 718 Name: "metrics.influxdb", 719 Usage: "Enable metrics export/push to an external InfluxDB database", 720 } 721 MetricsInfluxDBEndpointFlag = cli.StringFlag{ 722 Name: "metrics.influxdb.endpoint", 723 Usage: "InfluxDB API endpoint to report metrics to", 724 Value: metrics.DefaultConfig.InfluxDBEndpoint, 725 } 726 MetricsInfluxDBDatabaseFlag = cli.StringFlag{ 727 Name: "metrics.influxdb.database", 728 Usage: "InfluxDB database name to push reported metrics to", 729 Value: metrics.DefaultConfig.InfluxDBDatabase, 730 } 731 MetricsInfluxDBUsernameFlag = cli.StringFlag{ 732 Name: "metrics.influxdb.username", 733 Usage: "Username to authorize access to the database", 734 Value: metrics.DefaultConfig.InfluxDBUsername, 735 } 736 MetricsInfluxDBPasswordFlag = cli.StringFlag{ 737 Name: "metrics.influxdb.password", 738 Usage: "Password to authorize access to the database", 739 Value: metrics.DefaultConfig.InfluxDBPassword, 740 } 741 // Tags are part of every measurement sent to InfluxDB. Queries on tags are faster in InfluxDB. 742 // For example `host` tag could be used so that we can group all nodes and average a measurement 743 // across all of them, but also so that we can select a specific node and inspect its measurements. 744 // https://docs.influxdata.com/influxdb/v1.4/concepts/key_concepts/#tag-key 745 MetricsInfluxDBTagsFlag = cli.StringFlag{ 746 Name: "metrics.influxdb.tags", 747 Usage: "Comma-separated InfluxDB tags (key/values) attached to all measurements", 748 Value: metrics.DefaultConfig.InfluxDBTags, 749 } 750 751 MetricsEnableInfluxDBV2Flag = cli.BoolFlag{ 752 Name: "metrics.influxdbv2", 753 Usage: "Enable metrics export/push to an external InfluxDB v2 database", 754 } 755 756 MetricsInfluxDBTokenFlag = cli.StringFlag{ 757 Name: "metrics.influxdb.token", 758 Usage: "Token to authorize access to the database (v2 only)", 759 Value: metrics.DefaultConfig.InfluxDBToken, 760 } 761 762 MetricsInfluxDBBucketFlag = cli.StringFlag{ 763 Name: "metrics.influxdb.bucket", 764 Usage: "InfluxDB bucket name to push reported metrics to (v2 only)", 765 Value: metrics.DefaultConfig.InfluxDBBucket, 766 } 767 768 MetricsInfluxDBOrganizationFlag = cli.StringFlag{ 769 Name: "metrics.influxdb.organization", 770 Usage: "InfluxDB organization name (v2 only)", 771 Value: metrics.DefaultConfig.InfluxDBOrganization, 772 } 773 774 CatalystFlag = cli.BoolFlag{ 775 Name: "catalyst", 776 Usage: "Catalyst mode (eth2 integration testing)", 777 } 778 ) 779 780 // MakeDataDir retrieves the currently requested data directory, terminating 781 // if none (or the empty string) is specified. If the node is starting a testnet, 782 // then a subdirectory of the specified datadir will be used. 783 func MakeDataDir(ctx *cli.Context) string { 784 if path := ctx.GlobalString(DataDirFlag.Name); path != "" { 785 if ctx.GlobalBool(RopstenFlag.Name) { 786 // Maintain compatibility with older Geth configurations storing the 787 // Ropsten database in `testnet` instead of `ropsten`. 788 return filepath.Join(path, "ropsten") 789 } 790 if ctx.GlobalBool(RinkebyFlag.Name) { 791 return filepath.Join(path, "rinkeby") 792 } 793 if ctx.GlobalBool(GoerliFlag.Name) { 794 return filepath.Join(path, "goerli") 795 } 796 return path 797 } 798 Fatalf("Cannot determine default data directory, please set manually (--datadir)") 799 return "" 800 } 801 802 // setNodeKey creates a node key from set command line flags, either loading it 803 // from a file or as a specified hex value. If neither flags were provided, this 804 // method returns nil and an emphemeral key is to be generated. 805 func setNodeKey(ctx *cli.Context, cfg *p2p.Config) { 806 var ( 807 hex = ctx.GlobalString(NodeKeyHexFlag.Name) 808 file = ctx.GlobalString(NodeKeyFileFlag.Name) 809 key *ecdsa.PrivateKey 810 err error 811 ) 812 switch { 813 case file != "" && hex != "": 814 Fatalf("Options %q and %q are mutually exclusive", NodeKeyFileFlag.Name, NodeKeyHexFlag.Name) 815 case file != "": 816 if key, err = crypto.LoadECDSA(file); err != nil { 817 Fatalf("Option %q: %v", NodeKeyFileFlag.Name, err) 818 } 819 cfg.PrivateKey = key 820 case hex != "": 821 if key, err = crypto.HexToECDSA(hex); err != nil { 822 Fatalf("Option %q: %v", NodeKeyHexFlag.Name, err) 823 } 824 cfg.PrivateKey = key 825 } 826 } 827 828 // setNodeUserIdent creates the user identifier from CLI flags. 829 func setNodeUserIdent(ctx *cli.Context, cfg *node.Config) { 830 if identity := ctx.GlobalString(IdentityFlag.Name); len(identity) > 0 { 831 cfg.UserIdent = identity 832 } 833 } 834 835 // setBootstrapNodes creates a list of bootstrap nodes from the command line 836 // flags, reverting to pre-configured ones if none have been specified. 837 func setBootstrapNodes(ctx *cli.Context, cfg *p2p.Config) { 838 urls := params.MainnetBootnodes 839 switch { 840 case ctx.GlobalIsSet(BootnodesFlag.Name): 841 urls = SplitAndTrim(ctx.GlobalString(BootnodesFlag.Name)) 842 case ctx.GlobalBool(RopstenFlag.Name): 843 urls = params.RopstenBootnodes 844 case ctx.GlobalBool(RinkebyFlag.Name): 845 urls = params.RinkebyBootnodes 846 case ctx.GlobalBool(GoerliFlag.Name): 847 urls = params.GoerliBootnodes 848 case cfg.BootstrapNodes != nil: 849 return // already set, don't apply defaults. 850 } 851 852 cfg.BootstrapNodes = make([]*enode.Node, 0, len(urls)) 853 for _, url := range urls { 854 if url != "" { 855 node, err := enode.Parse(enode.ValidSchemes, url) 856 if err != nil { 857 log.Crit("Bootstrap URL invalid", "enode", url, "err", err) 858 continue 859 } 860 cfg.BootstrapNodes = append(cfg.BootstrapNodes, node) 861 } 862 } 863 } 864 865 // setBootstrapNodesV5 creates a list of bootstrap nodes from the command line 866 // flags, reverting to pre-configured ones if none have been specified. 867 func setBootstrapNodesV5(ctx *cli.Context, cfg *p2p.Config) { 868 urls := params.V5Bootnodes 869 switch { 870 case ctx.GlobalIsSet(BootnodesFlag.Name): 871 urls = SplitAndTrim(ctx.GlobalString(BootnodesFlag.Name)) 872 case cfg.BootstrapNodesV5 != nil: 873 return // already set, don't apply defaults. 874 } 875 876 cfg.BootstrapNodesV5 = make([]*enode.Node, 0, len(urls)) 877 for _, url := range urls { 878 if url != "" { 879 node, err := enode.Parse(enode.ValidSchemes, url) 880 if err != nil { 881 log.Error("Bootstrap URL invalid", "enode", url, "err", err) 882 continue 883 } 884 cfg.BootstrapNodesV5 = append(cfg.BootstrapNodesV5, node) 885 } 886 } 887 } 888 889 // setListenAddress creates a TCP listening address string from set command 890 // line flags. 891 func setListenAddress(ctx *cli.Context, cfg *p2p.Config) { 892 if ctx.GlobalIsSet(ListenPortFlag.Name) { 893 cfg.ListenAddr = fmt.Sprintf(":%d", ctx.GlobalInt(ListenPortFlag.Name)) 894 } 895 } 896 897 // setNAT creates a port mapper from command line flags. 898 func setNAT(ctx *cli.Context, cfg *p2p.Config) { 899 if ctx.GlobalIsSet(NATFlag.Name) { 900 natif, err := nat.Parse(ctx.GlobalString(NATFlag.Name)) 901 if err != nil { 902 Fatalf("Option %s: %v", NATFlag.Name, err) 903 } 904 cfg.NAT = natif 905 } 906 } 907 908 // SplitAndTrim splits input separated by a comma 909 // and trims excessive white space from the substrings. 910 func SplitAndTrim(input string) (ret []string) { 911 l := strings.Split(input, ",") 912 for _, r := range l { 913 if r = strings.TrimSpace(r); r != "" { 914 ret = append(ret, r) 915 } 916 } 917 return ret 918 } 919 920 // setHTTP creates the HTTP RPC listener interface string from the set 921 // command line flags, returning empty if the HTTP endpoint is disabled. 922 func setHTTP(ctx *cli.Context, cfg *node.Config) { 923 if ctx.GlobalBool(HTTPEnabledFlag.Name) && cfg.HTTPHost == "" { 924 cfg.HTTPHost = "127.0.0.1" 925 if ctx.GlobalIsSet(HTTPListenAddrFlag.Name) { 926 cfg.HTTPHost = ctx.GlobalString(HTTPListenAddrFlag.Name) 927 } 928 } 929 930 if ctx.GlobalIsSet(HTTPPortFlag.Name) { 931 cfg.HTTPPort = ctx.GlobalInt(HTTPPortFlag.Name) 932 } 933 934 if ctx.GlobalIsSet(HTTPCORSDomainFlag.Name) { 935 cfg.HTTPCors = SplitAndTrim(ctx.GlobalString(HTTPCORSDomainFlag.Name)) 936 } 937 938 if ctx.GlobalIsSet(HTTPApiFlag.Name) { 939 cfg.HTTPModules = SplitAndTrim(ctx.GlobalString(HTTPApiFlag.Name)) 940 } 941 942 if ctx.GlobalIsSet(HTTPVirtualHostsFlag.Name) { 943 cfg.HTTPVirtualHosts = SplitAndTrim(ctx.GlobalString(HTTPVirtualHostsFlag.Name)) 944 } 945 946 if ctx.GlobalIsSet(HTTPPathPrefixFlag.Name) { 947 cfg.HTTPPathPrefix = ctx.GlobalString(HTTPPathPrefixFlag.Name) 948 } 949 if ctx.GlobalIsSet(AllowUnprotectedTxs.Name) { 950 cfg.AllowUnprotectedTxs = ctx.GlobalBool(AllowUnprotectedTxs.Name) 951 } 952 } 953 954 // setGraphQL creates the GraphQL listener interface string from the set 955 // command line flags, returning empty if the GraphQL endpoint is disabled. 956 func setGraphQL(ctx *cli.Context, cfg *node.Config) { 957 if ctx.GlobalIsSet(GraphQLCORSDomainFlag.Name) { 958 cfg.GraphQLCors = SplitAndTrim(ctx.GlobalString(GraphQLCORSDomainFlag.Name)) 959 } 960 if ctx.GlobalIsSet(GraphQLVirtualHostsFlag.Name) { 961 cfg.GraphQLVirtualHosts = SplitAndTrim(ctx.GlobalString(GraphQLVirtualHostsFlag.Name)) 962 } 963 } 964 965 // setWS creates the WebSocket RPC listener interface string from the set 966 // command line flags, returning empty if the HTTP endpoint is disabled. 967 func setWS(ctx *cli.Context, cfg *node.Config) { 968 if ctx.GlobalBool(WSEnabledFlag.Name) && cfg.WSHost == "" { 969 cfg.WSHost = "127.0.0.1" 970 if ctx.GlobalIsSet(WSListenAddrFlag.Name) { 971 cfg.WSHost = ctx.GlobalString(WSListenAddrFlag.Name) 972 } 973 } 974 if ctx.GlobalIsSet(WSPortFlag.Name) { 975 cfg.WSPort = ctx.GlobalInt(WSPortFlag.Name) 976 } 977 978 if ctx.GlobalIsSet(WSAllowedOriginsFlag.Name) { 979 cfg.WSOrigins = SplitAndTrim(ctx.GlobalString(WSAllowedOriginsFlag.Name)) 980 } 981 982 if ctx.GlobalIsSet(WSApiFlag.Name) { 983 cfg.WSModules = SplitAndTrim(ctx.GlobalString(WSApiFlag.Name)) 984 } 985 986 if ctx.GlobalIsSet(WSPathPrefixFlag.Name) { 987 cfg.WSPathPrefix = ctx.GlobalString(WSPathPrefixFlag.Name) 988 } 989 } 990 991 // setIPC creates an IPC path configuration from the set command line flags, 992 // returning an empty string if IPC was explicitly disabled, or the set path. 993 func setIPC(ctx *cli.Context, cfg *node.Config) { 994 CheckExclusive(ctx, IPCDisabledFlag, IPCPathFlag) 995 switch { 996 case ctx.GlobalBool(IPCDisabledFlag.Name): 997 cfg.IPCPath = "" 998 case ctx.GlobalIsSet(IPCPathFlag.Name): 999 cfg.IPCPath = ctx.GlobalString(IPCPathFlag.Name) 1000 } 1001 } 1002 1003 // setLes configures the les server and ultra light client settings from the command line flags. 1004 func setLes(ctx *cli.Context, cfg *ethconfig.Config) { 1005 if ctx.GlobalIsSet(LightServeFlag.Name) { 1006 cfg.LightServ = ctx.GlobalInt(LightServeFlag.Name) 1007 } 1008 if ctx.GlobalIsSet(LightIngressFlag.Name) { 1009 cfg.LightIngress = ctx.GlobalInt(LightIngressFlag.Name) 1010 } 1011 if ctx.GlobalIsSet(LightEgressFlag.Name) { 1012 cfg.LightEgress = ctx.GlobalInt(LightEgressFlag.Name) 1013 } 1014 if ctx.GlobalIsSet(LightMaxPeersFlag.Name) { 1015 cfg.LightPeers = ctx.GlobalInt(LightMaxPeersFlag.Name) 1016 } 1017 if ctx.GlobalIsSet(UltraLightServersFlag.Name) { 1018 cfg.UltraLightServers = strings.Split(ctx.GlobalString(UltraLightServersFlag.Name), ",") 1019 } 1020 if ctx.GlobalIsSet(UltraLightFractionFlag.Name) { 1021 cfg.UltraLightFraction = ctx.GlobalInt(UltraLightFractionFlag.Name) 1022 } 1023 if cfg.UltraLightFraction <= 0 && cfg.UltraLightFraction > 100 { 1024 log.Error("Ultra light fraction is invalid", "had", cfg.UltraLightFraction, "updated", ethconfig.Defaults.UltraLightFraction) 1025 cfg.UltraLightFraction = ethconfig.Defaults.UltraLightFraction 1026 } 1027 if ctx.GlobalIsSet(UltraLightOnlyAnnounceFlag.Name) { 1028 cfg.UltraLightOnlyAnnounce = ctx.GlobalBool(UltraLightOnlyAnnounceFlag.Name) 1029 } 1030 if ctx.GlobalIsSet(LightNoPruneFlag.Name) { 1031 cfg.LightNoPrune = ctx.GlobalBool(LightNoPruneFlag.Name) 1032 } 1033 if ctx.GlobalIsSet(LightNoSyncServeFlag.Name) { 1034 cfg.LightNoSyncServe = ctx.GlobalBool(LightNoSyncServeFlag.Name) 1035 } 1036 } 1037 1038 // MakeDatabaseHandles raises out the number of allowed file handles per process 1039 // for Geth and returns half of the allowance to assign to the database. 1040 func MakeDatabaseHandles() int { 1041 limit, err := fdlimit.Maximum() 1042 if err != nil { 1043 Fatalf("Failed to retrieve file descriptor allowance: %v", err) 1044 } 1045 raised, err := fdlimit.Raise(uint64(limit)) 1046 if err != nil { 1047 Fatalf("Failed to raise file descriptor allowance: %v", err) 1048 } 1049 return int(raised / 2) // Leave half for networking and other stuff 1050 } 1051 1052 // MakeAddress converts an account specified directly as a hex encoded string or 1053 // a key index in the key store to an internal account representation. 1054 func MakeAddress(ks *keystore.KeyStore, account string) (accounts.Account, error) { 1055 // If the specified account is a valid address, return it 1056 if common.IsHexAddress(account) { 1057 return accounts.Account{Address: common.HexToAddress(account)}, nil 1058 } 1059 // Otherwise try to interpret the account as a keystore index 1060 index, err := strconv.Atoi(account) 1061 if err != nil || index < 0 { 1062 return accounts.Account{}, fmt.Errorf("invalid account address or index %q", account) 1063 } 1064 log.Warn("-------------------------------------------------------------------") 1065 log.Warn("Referring to accounts by order in the keystore folder is dangerous!") 1066 log.Warn("This functionality is deprecated and will be removed in the future!") 1067 log.Warn("Please use explicit addresses! (can search via `geth account list`)") 1068 log.Warn("-------------------------------------------------------------------") 1069 1070 accs := ks.Accounts() 1071 if len(accs) <= index { 1072 return accounts.Account{}, fmt.Errorf("index %d higher than number of accounts %d", index, len(accs)) 1073 } 1074 return accs[index], nil 1075 } 1076 1077 // setEtherbase retrieves the etherbase either from the directly specified 1078 // command line flags or from the keystore if CLI indexed. 1079 func setEtherbase(ctx *cli.Context, ks *keystore.KeyStore, cfg *ethconfig.Config) { 1080 // Extract the current etherbase 1081 var etherbase string 1082 if ctx.GlobalIsSet(MinerEtherbaseFlag.Name) { 1083 etherbase = ctx.GlobalString(MinerEtherbaseFlag.Name) 1084 } 1085 // Convert the etherbase into an address and configure it 1086 if etherbase != "" { 1087 if ks != nil { 1088 account, err := MakeAddress(ks, etherbase) 1089 if err != nil { 1090 Fatalf("Invalid miner etherbase: %v", err) 1091 } 1092 cfg.Miner.Etherbase = account.Address 1093 } else { 1094 Fatalf("No etherbase configured") 1095 } 1096 } 1097 } 1098 1099 // MakePasswordList reads password lines from the file specified by the global --password flag. 1100 func MakePasswordList(ctx *cli.Context) []string { 1101 path := ctx.GlobalString(PasswordFileFlag.Name) 1102 if path == "" { 1103 return nil 1104 } 1105 text, err := ioutil.ReadFile(path) 1106 if err != nil { 1107 Fatalf("Failed to read password file: %v", err) 1108 } 1109 lines := strings.Split(string(text), "\n") 1110 // Sanitise DOS line endings. 1111 for i := range lines { 1112 lines[i] = strings.TrimRight(lines[i], "\r") 1113 } 1114 return lines 1115 } 1116 1117 func SetP2PConfig(ctx *cli.Context, cfg *p2p.Config) { 1118 setNodeKey(ctx, cfg) 1119 setNAT(ctx, cfg) 1120 setListenAddress(ctx, cfg) 1121 setBootstrapNodes(ctx, cfg) 1122 setBootstrapNodesV5(ctx, cfg) 1123 1124 lightClient := ctx.GlobalString(SyncModeFlag.Name) == "light" 1125 lightServer := (ctx.GlobalInt(LightServeFlag.Name) != 0) 1126 1127 lightPeers := ctx.GlobalInt(LightMaxPeersFlag.Name) 1128 if lightClient && !ctx.GlobalIsSet(LightMaxPeersFlag.Name) { 1129 // dynamic default - for clients we use 1/10th of the default for servers 1130 lightPeers /= 10 1131 } 1132 1133 if ctx.GlobalIsSet(MaxPeersFlag.Name) { 1134 cfg.MaxPeers = ctx.GlobalInt(MaxPeersFlag.Name) 1135 if lightServer && !ctx.GlobalIsSet(LightMaxPeersFlag.Name) { 1136 cfg.MaxPeers += lightPeers 1137 } 1138 } else { 1139 if lightServer { 1140 cfg.MaxPeers += lightPeers 1141 } 1142 if lightClient && ctx.GlobalIsSet(LightMaxPeersFlag.Name) && cfg.MaxPeers < lightPeers { 1143 cfg.MaxPeers = lightPeers 1144 } 1145 } 1146 if !(lightClient || lightServer) { 1147 lightPeers = 0 1148 } 1149 ethPeers := cfg.MaxPeers - lightPeers 1150 if lightClient { 1151 ethPeers = 0 1152 } 1153 log.Info("Maximum peer count", "ETH", ethPeers, "LES", lightPeers, "total", cfg.MaxPeers) 1154 1155 if ctx.GlobalIsSet(MaxPendingPeersFlag.Name) { 1156 cfg.MaxPendingPeers = ctx.GlobalInt(MaxPendingPeersFlag.Name) 1157 } 1158 if ctx.GlobalIsSet(NoDiscoverFlag.Name) || lightClient { 1159 cfg.NoDiscovery = true 1160 } 1161 1162 // if we're running a light client or server, force enable the v5 peer discovery 1163 // unless it is explicitly disabled with --nodiscover note that explicitly specifying 1164 // --v5disc overrides --nodiscover, in which case the later only disables v4 discovery 1165 forceV5Discovery := (lightClient || lightServer) && !ctx.GlobalBool(NoDiscoverFlag.Name) 1166 if ctx.GlobalIsSet(DiscoveryV5Flag.Name) { 1167 cfg.DiscoveryV5 = ctx.GlobalBool(DiscoveryV5Flag.Name) 1168 } else if forceV5Discovery { 1169 cfg.DiscoveryV5 = true 1170 } 1171 1172 if netrestrict := ctx.GlobalString(NetrestrictFlag.Name); netrestrict != "" { 1173 list, err := netutil.ParseNetlist(netrestrict) 1174 if err != nil { 1175 Fatalf("Option %q: %v", NetrestrictFlag.Name, err) 1176 } 1177 cfg.NetRestrict = list 1178 } 1179 1180 if ctx.GlobalBool(DeveloperFlag.Name) || ctx.GlobalBool(CatalystFlag.Name) { 1181 // --dev mode can't use p2p networking. 1182 cfg.MaxPeers = 0 1183 cfg.ListenAddr = "" 1184 cfg.NoDial = true 1185 cfg.NoDiscovery = true 1186 cfg.DiscoveryV5 = false 1187 } 1188 } 1189 1190 // SetNodeConfig applies node-related command line flags to the config. 1191 func SetNodeConfig(ctx *cli.Context, cfg *node.Config) { 1192 SetP2PConfig(ctx, &cfg.P2P) 1193 setIPC(ctx, cfg) 1194 setHTTP(ctx, cfg) 1195 setGraphQL(ctx, cfg) 1196 setWS(ctx, cfg) 1197 setNodeUserIdent(ctx, cfg) 1198 setDataDir(ctx, cfg) 1199 setSmartCard(ctx, cfg) 1200 1201 if ctx.GlobalIsSet(ExternalSignerFlag.Name) { 1202 cfg.ExternalSigner = ctx.GlobalString(ExternalSignerFlag.Name) 1203 } 1204 1205 if ctx.GlobalIsSet(KeyStoreDirFlag.Name) { 1206 cfg.KeyStoreDir = ctx.GlobalString(KeyStoreDirFlag.Name) 1207 } 1208 if ctx.GlobalIsSet(DeveloperFlag.Name) { 1209 cfg.UseLightweightKDF = true 1210 } 1211 if ctx.GlobalIsSet(LightKDFFlag.Name) { 1212 cfg.UseLightweightKDF = ctx.GlobalBool(LightKDFFlag.Name) 1213 } 1214 if ctx.GlobalIsSet(NoUSBFlag.Name) || cfg.NoUSB { 1215 log.Warn("Option nousb is deprecated and USB is deactivated by default. Use --usb to enable") 1216 } 1217 if ctx.GlobalIsSet(USBFlag.Name) { 1218 cfg.USB = ctx.GlobalBool(USBFlag.Name) 1219 } 1220 if ctx.GlobalIsSet(InsecureUnlockAllowedFlag.Name) { 1221 cfg.InsecureUnlockAllowed = ctx.GlobalBool(InsecureUnlockAllowedFlag.Name) 1222 } 1223 } 1224 1225 func setSmartCard(ctx *cli.Context, cfg *node.Config) { 1226 // Skip enabling smartcards if no path is set 1227 path := ctx.GlobalString(SmartCardDaemonPathFlag.Name) 1228 if path == "" { 1229 return 1230 } 1231 // Sanity check that the smartcard path is valid 1232 fi, err := os.Stat(path) 1233 if err != nil { 1234 log.Info("Smartcard socket not found, disabling", "err", err) 1235 return 1236 } 1237 if fi.Mode()&os.ModeType != os.ModeSocket { 1238 log.Error("Invalid smartcard daemon path", "path", path, "type", fi.Mode().String()) 1239 return 1240 } 1241 // Smartcard daemon path exists and is a socket, enable it 1242 cfg.SmartCardDaemonPath = path 1243 } 1244 1245 func setDataDir(ctx *cli.Context, cfg *node.Config) { 1246 switch { 1247 case ctx.GlobalIsSet(DataDirFlag.Name): 1248 cfg.DataDir = ctx.GlobalString(DataDirFlag.Name) 1249 case ctx.GlobalBool(DeveloperFlag.Name): 1250 cfg.DataDir = "" // unless explicitly requested, use memory databases 1251 case ctx.GlobalBool(RopstenFlag.Name) && cfg.DataDir == node.DefaultDataDir(): 1252 // Maintain compatibility with older Geth configurations storing the 1253 // Ropsten database in `testnet` instead of `ropsten`. 1254 legacyPath := filepath.Join(node.DefaultDataDir(), "testnet") 1255 if _, err := os.Stat(legacyPath); !os.IsNotExist(err) { 1256 log.Warn("Using the deprecated `testnet` datadir. Future versions will store the Ropsten chain in `ropsten`.") 1257 cfg.DataDir = legacyPath 1258 } else { 1259 cfg.DataDir = filepath.Join(node.DefaultDataDir(), "ropsten") 1260 } 1261 1262 cfg.DataDir = filepath.Join(node.DefaultDataDir(), "ropsten") 1263 case ctx.GlobalBool(RinkebyFlag.Name) && cfg.DataDir == node.DefaultDataDir(): 1264 cfg.DataDir = filepath.Join(node.DefaultDataDir(), "rinkeby") 1265 case ctx.GlobalBool(GoerliFlag.Name) && cfg.DataDir == node.DefaultDataDir(): 1266 cfg.DataDir = filepath.Join(node.DefaultDataDir(), "goerli") 1267 } 1268 } 1269 1270 func setGPO(ctx *cli.Context, cfg *gasprice.Config, light bool) { 1271 // If we are running the light client, apply another group 1272 // settings for gas oracle. 1273 if light { 1274 *cfg = ethconfig.LightClientGPO 1275 } 1276 if ctx.GlobalIsSet(GpoBlocksFlag.Name) { 1277 cfg.Blocks = ctx.GlobalInt(GpoBlocksFlag.Name) 1278 } 1279 if ctx.GlobalIsSet(GpoPercentileFlag.Name) { 1280 cfg.Percentile = ctx.GlobalInt(GpoPercentileFlag.Name) 1281 } 1282 if ctx.GlobalIsSet(GpoMaxGasPriceFlag.Name) { 1283 cfg.MaxPrice = big.NewInt(ctx.GlobalInt64(GpoMaxGasPriceFlag.Name)) 1284 } 1285 if ctx.GlobalIsSet(GpoIgnoreGasPriceFlag.Name) { 1286 cfg.IgnorePrice = big.NewInt(ctx.GlobalInt64(GpoIgnoreGasPriceFlag.Name)) 1287 } 1288 } 1289 1290 func setTxPool(ctx *cli.Context, cfg *core.TxPoolConfig) { 1291 if ctx.GlobalIsSet(TxPoolLocalsFlag.Name) { 1292 locals := strings.Split(ctx.GlobalString(TxPoolLocalsFlag.Name), ",") 1293 for _, account := range locals { 1294 if trimmed := strings.TrimSpace(account); !common.IsHexAddress(trimmed) { 1295 Fatalf("Invalid account in --txpool.locals: %s", trimmed) 1296 } else { 1297 cfg.Locals = append(cfg.Locals, common.HexToAddress(account)) 1298 } 1299 } 1300 } 1301 if ctx.GlobalIsSet(TxPoolNoLocalsFlag.Name) { 1302 cfg.NoLocals = ctx.GlobalBool(TxPoolNoLocalsFlag.Name) 1303 } 1304 if ctx.GlobalIsSet(TxPoolJournalFlag.Name) { 1305 cfg.Journal = ctx.GlobalString(TxPoolJournalFlag.Name) 1306 } 1307 if ctx.GlobalIsSet(TxPoolRejournalFlag.Name) { 1308 cfg.Rejournal = ctx.GlobalDuration(TxPoolRejournalFlag.Name) 1309 } 1310 if ctx.GlobalIsSet(TxPoolPriceLimitFlag.Name) { 1311 cfg.PriceLimit = ctx.GlobalUint64(TxPoolPriceLimitFlag.Name) 1312 } 1313 if ctx.GlobalIsSet(TxPoolPriceBumpFlag.Name) { 1314 cfg.PriceBump = ctx.GlobalUint64(TxPoolPriceBumpFlag.Name) 1315 } 1316 if ctx.GlobalIsSet(TxPoolAccountSlotsFlag.Name) { 1317 cfg.AccountSlots = ctx.GlobalUint64(TxPoolAccountSlotsFlag.Name) 1318 } 1319 if ctx.GlobalIsSet(TxPoolGlobalSlotsFlag.Name) { 1320 cfg.GlobalSlots = ctx.GlobalUint64(TxPoolGlobalSlotsFlag.Name) 1321 } 1322 if ctx.GlobalIsSet(TxPoolAccountQueueFlag.Name) { 1323 cfg.AccountQueue = ctx.GlobalUint64(TxPoolAccountQueueFlag.Name) 1324 } 1325 if ctx.GlobalIsSet(TxPoolGlobalQueueFlag.Name) { 1326 cfg.GlobalQueue = ctx.GlobalUint64(TxPoolGlobalQueueFlag.Name) 1327 } 1328 if ctx.GlobalIsSet(TxPoolLifetimeFlag.Name) { 1329 cfg.Lifetime = ctx.GlobalDuration(TxPoolLifetimeFlag.Name) 1330 } 1331 } 1332 1333 func setEthash(ctx *cli.Context, cfg *ethconfig.Config) { 1334 if ctx.GlobalIsSet(EthashCacheDirFlag.Name) { 1335 cfg.Ethash.CacheDir = ctx.GlobalString(EthashCacheDirFlag.Name) 1336 } 1337 if ctx.GlobalIsSet(EthashDatasetDirFlag.Name) { 1338 cfg.Ethash.DatasetDir = ctx.GlobalString(EthashDatasetDirFlag.Name) 1339 } 1340 if ctx.GlobalIsSet(EthashCachesInMemoryFlag.Name) { 1341 cfg.Ethash.CachesInMem = ctx.GlobalInt(EthashCachesInMemoryFlag.Name) 1342 } 1343 if ctx.GlobalIsSet(EthashCachesOnDiskFlag.Name) { 1344 cfg.Ethash.CachesOnDisk = ctx.GlobalInt(EthashCachesOnDiskFlag.Name) 1345 } 1346 if ctx.GlobalIsSet(EthashCachesLockMmapFlag.Name) { 1347 cfg.Ethash.CachesLockMmap = ctx.GlobalBool(EthashCachesLockMmapFlag.Name) 1348 } 1349 if ctx.GlobalIsSet(EthashDatasetsInMemoryFlag.Name) { 1350 cfg.Ethash.DatasetsInMem = ctx.GlobalInt(EthashDatasetsInMemoryFlag.Name) 1351 } 1352 if ctx.GlobalIsSet(EthashDatasetsOnDiskFlag.Name) { 1353 cfg.Ethash.DatasetsOnDisk = ctx.GlobalInt(EthashDatasetsOnDiskFlag.Name) 1354 } 1355 if ctx.GlobalIsSet(EthashDatasetsLockMmapFlag.Name) { 1356 cfg.Ethash.DatasetsLockMmap = ctx.GlobalBool(EthashDatasetsLockMmapFlag.Name) 1357 } 1358 } 1359 1360 func setMiner(ctx *cli.Context, cfg *miner.Config) { 1361 if ctx.GlobalIsSet(MinerNotifyFlag.Name) { 1362 cfg.Notify = strings.Split(ctx.GlobalString(MinerNotifyFlag.Name), ",") 1363 } 1364 cfg.NotifyFull = ctx.GlobalBool(MinerNotifyFullFlag.Name) 1365 if ctx.GlobalIsSet(MinerExtraDataFlag.Name) { 1366 cfg.ExtraData = []byte(ctx.GlobalString(MinerExtraDataFlag.Name)) 1367 } 1368 if ctx.GlobalIsSet(MinerGasLimitFlag.Name) { 1369 cfg.GasCeil = ctx.GlobalUint64(MinerGasLimitFlag.Name) 1370 } 1371 if ctx.GlobalIsSet(MinerGasPriceFlag.Name) { 1372 cfg.GasPrice = GlobalBig(ctx, MinerGasPriceFlag.Name) 1373 } 1374 if ctx.GlobalIsSet(MinerRecommitIntervalFlag.Name) { 1375 cfg.Recommit = ctx.GlobalDuration(MinerRecommitIntervalFlag.Name) 1376 } 1377 if ctx.GlobalIsSet(MinerNoVerifyFlag.Name) { 1378 cfg.Noverify = ctx.GlobalBool(MinerNoVerifyFlag.Name) 1379 } 1380 if ctx.GlobalIsSet(LegacyMinerGasTargetFlag.Name) { 1381 log.Warn("The generic --miner.gastarget flag is deprecated and will be removed in the future!") 1382 } 1383 } 1384 1385 func setWhitelist(ctx *cli.Context, cfg *ethconfig.Config) { 1386 whitelist := ctx.GlobalString(WhitelistFlag.Name) 1387 if whitelist == "" { 1388 return 1389 } 1390 cfg.Whitelist = make(map[uint64]common.Hash) 1391 for _, entry := range strings.Split(whitelist, ",") { 1392 parts := strings.Split(entry, "=") 1393 if len(parts) != 2 { 1394 Fatalf("Invalid whitelist entry: %s", entry) 1395 } 1396 number, err := strconv.ParseUint(parts[0], 0, 64) 1397 if err != nil { 1398 Fatalf("Invalid whitelist block number %s: %v", parts[0], err) 1399 } 1400 var hash common.Hash 1401 if err = hash.UnmarshalText([]byte(parts[1])); err != nil { 1402 Fatalf("Invalid whitelist hash %s: %v", parts[1], err) 1403 } 1404 cfg.Whitelist[number] = hash 1405 } 1406 } 1407 1408 // CheckExclusive verifies that only a single instance of the provided flags was 1409 // set by the user. Each flag might optionally be followed by a string type to 1410 // specialize it further. 1411 func CheckExclusive(ctx *cli.Context, args ...interface{}) { 1412 set := make([]string, 0, 1) 1413 for i := 0; i < len(args); i++ { 1414 // Make sure the next argument is a flag and skip if not set 1415 flag, ok := args[i].(cli.Flag) 1416 if !ok { 1417 panic(fmt.Sprintf("invalid argument, not cli.Flag type: %T", args[i])) 1418 } 1419 // Check if next arg extends current and expand its name if so 1420 name := flag.GetName() 1421 1422 if i+1 < len(args) { 1423 switch option := args[i+1].(type) { 1424 case string: 1425 // Extended flag check, make sure value set doesn't conflict with passed in option 1426 if ctx.GlobalString(flag.GetName()) == option { 1427 name += "=" + option 1428 set = append(set, "--"+name) 1429 } 1430 // shift arguments and continue 1431 i++ 1432 continue 1433 1434 case cli.Flag: 1435 default: 1436 panic(fmt.Sprintf("invalid argument, not cli.Flag or string extension: %T", args[i+1])) 1437 } 1438 } 1439 // Mark the flag if it's set 1440 if ctx.GlobalIsSet(flag.GetName()) { 1441 set = append(set, "--"+name) 1442 } 1443 } 1444 if len(set) > 1 { 1445 Fatalf("Flags %v can't be used at the same time", strings.Join(set, ", ")) 1446 } 1447 } 1448 1449 // SetEthConfig applies eth-related command line flags to the config. 1450 func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { 1451 // Avoid conflicting network flags 1452 CheckExclusive(ctx, MainnetFlag, DeveloperFlag, RopstenFlag, RinkebyFlag, GoerliFlag) 1453 CheckExclusive(ctx, LightServeFlag, SyncModeFlag, "light") 1454 CheckExclusive(ctx, DeveloperFlag, ExternalSignerFlag) // Can't use both ephemeral unlocked and external signer 1455 if ctx.GlobalString(GCModeFlag.Name) == "archive" && ctx.GlobalUint64(TxLookupLimitFlag.Name) != 0 { 1456 ctx.GlobalSet(TxLookupLimitFlag.Name, "0") 1457 log.Warn("Disable transaction unindexing for archive node") 1458 } 1459 if ctx.GlobalIsSet(LightServeFlag.Name) && ctx.GlobalUint64(TxLookupLimitFlag.Name) != 0 { 1460 log.Warn("LES server cannot serve old transaction status and cannot connect below les/4 protocol version if transaction lookup index is limited") 1461 } 1462 var ks *keystore.KeyStore 1463 if keystores := stack.AccountManager().Backends(keystore.KeyStoreType); len(keystores) > 0 { 1464 ks = keystores[0].(*keystore.KeyStore) 1465 } 1466 setEtherbase(ctx, ks, cfg) 1467 setGPO(ctx, &cfg.GPO, ctx.GlobalString(SyncModeFlag.Name) == "light") 1468 setTxPool(ctx, &cfg.TxPool) 1469 setEthash(ctx, cfg) 1470 setMiner(ctx, &cfg.Miner) 1471 setWhitelist(ctx, cfg) 1472 setLes(ctx, cfg) 1473 1474 // Cap the cache allowance and tune the garbage collector 1475 mem, err := gopsutil.VirtualMemory() 1476 if err == nil { 1477 if 32<<(^uintptr(0)>>63) == 32 && mem.Total > 2*1024*1024*1024 { 1478 log.Warn("Lowering memory allowance on 32bit arch", "available", mem.Total/1024/1024, "addressable", 2*1024) 1479 mem.Total = 2 * 1024 * 1024 * 1024 1480 } 1481 allowance := int(mem.Total / 1024 / 1024 / 3) 1482 if cache := ctx.GlobalInt(CacheFlag.Name); cache > allowance { 1483 log.Warn("Sanitizing cache to Go's GC limits", "provided", cache, "updated", allowance) 1484 ctx.GlobalSet(CacheFlag.Name, strconv.Itoa(allowance)) 1485 } 1486 } 1487 // Ensure Go's GC ignores the database cache for trigger percentage 1488 cache := ctx.GlobalInt(CacheFlag.Name) 1489 gogc := math.Max(20, math.Min(100, 100/(float64(cache)/1024))) 1490 1491 log.Debug("Sanitizing Go's GC trigger", "percent", int(gogc)) 1492 godebug.SetGCPercent(int(gogc)) 1493 1494 if ctx.GlobalIsSet(SyncModeFlag.Name) { 1495 cfg.SyncMode = *GlobalTextMarshaler(ctx, SyncModeFlag.Name).(*downloader.SyncMode) 1496 } 1497 if ctx.GlobalIsSet(NetworkIdFlag.Name) { 1498 cfg.NetworkId = ctx.GlobalUint64(NetworkIdFlag.Name) 1499 } 1500 if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheDatabaseFlag.Name) { 1501 cfg.DatabaseCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheDatabaseFlag.Name) / 100 1502 } 1503 cfg.DatabaseHandles = MakeDatabaseHandles() 1504 if ctx.GlobalIsSet(AncientFlag.Name) { 1505 cfg.DatabaseFreezer = ctx.GlobalString(AncientFlag.Name) 1506 } 1507 1508 if gcmode := ctx.GlobalString(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" { 1509 Fatalf("--%s must be either 'full' or 'archive'", GCModeFlag.Name) 1510 } 1511 if ctx.GlobalIsSet(GCModeFlag.Name) { 1512 cfg.NoPruning = ctx.GlobalString(GCModeFlag.Name) == "archive" 1513 } 1514 if ctx.GlobalIsSet(CacheNoPrefetchFlag.Name) { 1515 cfg.NoPrefetch = ctx.GlobalBool(CacheNoPrefetchFlag.Name) 1516 } 1517 // Read the value from the flag no matter if it's set or not. 1518 cfg.Preimages = ctx.GlobalBool(CachePreimagesFlag.Name) 1519 if cfg.NoPruning && !cfg.Preimages { 1520 cfg.Preimages = true 1521 log.Info("Enabling recording of key preimages since archive mode is used") 1522 } 1523 if ctx.GlobalIsSet(TxLookupLimitFlag.Name) { 1524 cfg.TxLookupLimit = ctx.GlobalUint64(TxLookupLimitFlag.Name) 1525 } 1526 if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheTrieFlag.Name) { 1527 cfg.TrieCleanCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheTrieFlag.Name) / 100 1528 } 1529 if ctx.GlobalIsSet(CacheTrieJournalFlag.Name) { 1530 cfg.TrieCleanCacheJournal = ctx.GlobalString(CacheTrieJournalFlag.Name) 1531 } 1532 if ctx.GlobalIsSet(CacheTrieRejournalFlag.Name) { 1533 cfg.TrieCleanCacheRejournal = ctx.GlobalDuration(CacheTrieRejournalFlag.Name) 1534 } 1535 if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheGCFlag.Name) { 1536 cfg.TrieDirtyCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheGCFlag.Name) / 100 1537 } 1538 if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheSnapshotFlag.Name) { 1539 cfg.SnapshotCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheSnapshotFlag.Name) / 100 1540 } 1541 if !ctx.GlobalBool(SnapshotFlag.Name) { 1542 // If snap-sync is requested, this flag is also required 1543 if cfg.SyncMode == downloader.SnapSync { 1544 log.Info("Snap sync requested, enabling --snapshot") 1545 } else { 1546 cfg.TrieCleanCache += cfg.SnapshotCache 1547 cfg.SnapshotCache = 0 // Disabled 1548 } 1549 } 1550 if ctx.GlobalIsSet(DocRootFlag.Name) { 1551 cfg.DocRoot = ctx.GlobalString(DocRootFlag.Name) 1552 } 1553 if ctx.GlobalIsSet(VMEnableDebugFlag.Name) { 1554 // TODO(fjl): force-enable this in --dev mode 1555 cfg.EnablePreimageRecording = ctx.GlobalBool(VMEnableDebugFlag.Name) 1556 } 1557 1558 if ctx.GlobalIsSet(RPCGlobalGasCapFlag.Name) { 1559 cfg.RPCGasCap = ctx.GlobalUint64(RPCGlobalGasCapFlag.Name) 1560 } 1561 if cfg.RPCGasCap != 0 { 1562 log.Info("Set global gas cap", "cap", cfg.RPCGasCap) 1563 } else { 1564 log.Info("Global gas cap disabled") 1565 } 1566 if ctx.GlobalIsSet(RPCGlobalTxFeeCapFlag.Name) { 1567 cfg.RPCTxFeeCap = ctx.GlobalFloat64(RPCGlobalTxFeeCapFlag.Name) 1568 } 1569 if ctx.GlobalIsSet(NoDiscoverFlag.Name) { 1570 cfg.EthDiscoveryURLs, cfg.SnapDiscoveryURLs = []string{}, []string{} 1571 } else if ctx.GlobalIsSet(DNSDiscoveryFlag.Name) { 1572 urls := ctx.GlobalString(DNSDiscoveryFlag.Name) 1573 if urls == "" { 1574 cfg.EthDiscoveryURLs = []string{} 1575 } else { 1576 cfg.EthDiscoveryURLs = SplitAndTrim(urls) 1577 } 1578 } 1579 // Override any default configs for hard coded networks. 1580 switch { 1581 case ctx.GlobalBool(MainnetFlag.Name): 1582 if !ctx.GlobalIsSet(NetworkIdFlag.Name) { 1583 cfg.NetworkId = 1 1584 } 1585 cfg.Genesis = core.DefaultGenesisBlock() 1586 SetDNSDiscoveryDefaults(cfg, params.MainnetGenesisHash) 1587 case ctx.GlobalBool(RopstenFlag.Name): 1588 if !ctx.GlobalIsSet(NetworkIdFlag.Name) { 1589 cfg.NetworkId = 3 1590 } 1591 cfg.Genesis = core.DefaultRopstenGenesisBlock() 1592 SetDNSDiscoveryDefaults(cfg, params.RopstenGenesisHash) 1593 case ctx.GlobalBool(RinkebyFlag.Name): 1594 if !ctx.GlobalIsSet(NetworkIdFlag.Name) { 1595 cfg.NetworkId = 4 1596 } 1597 cfg.Genesis = core.DefaultRinkebyGenesisBlock() 1598 SetDNSDiscoveryDefaults(cfg, params.RinkebyGenesisHash) 1599 case ctx.GlobalBool(GoerliFlag.Name): 1600 if !ctx.GlobalIsSet(NetworkIdFlag.Name) { 1601 cfg.NetworkId = 5 1602 } 1603 cfg.Genesis = core.DefaultGoerliGenesisBlock() 1604 SetDNSDiscoveryDefaults(cfg, params.GoerliGenesisHash) 1605 case ctx.GlobalBool(DeveloperFlag.Name): 1606 if !ctx.GlobalIsSet(NetworkIdFlag.Name) { 1607 cfg.NetworkId = 1337 1608 } 1609 cfg.SyncMode = downloader.FullSync 1610 // Create new developer account or reuse existing one 1611 var ( 1612 developer accounts.Account 1613 passphrase string 1614 err error 1615 ) 1616 if list := MakePasswordList(ctx); len(list) > 0 { 1617 // Just take the first value. Although the function returns a possible multiple values and 1618 // some usages iterate through them as attempts, that doesn't make sense in this setting, 1619 // when we're definitely concerned with only one account. 1620 passphrase = list[0] 1621 } 1622 // setEtherbase has been called above, configuring the miner address from command line flags. 1623 if cfg.Miner.Etherbase != (common.Address{}) { 1624 developer = accounts.Account{Address: cfg.Miner.Etherbase} 1625 } else if accs := ks.Accounts(); len(accs) > 0 { 1626 developer = ks.Accounts()[0] 1627 } else { 1628 developer, err = ks.NewAccount(passphrase) 1629 if err != nil { 1630 Fatalf("Failed to create developer account: %v", err) 1631 } 1632 } 1633 if err := ks.Unlock(developer, passphrase); err != nil { 1634 Fatalf("Failed to unlock developer account: %v", err) 1635 } 1636 log.Info("Using developer account", "address", developer.Address) 1637 1638 // Create a new developer genesis block or reuse existing one 1639 cfg.Genesis = core.DeveloperGenesisBlock(uint64(ctx.GlobalInt(DeveloperPeriodFlag.Name)), developer.Address) 1640 if ctx.GlobalIsSet(DataDirFlag.Name) { 1641 // Check if we have an already initialized chain and fall back to 1642 // that if so. Otherwise we need to generate a new genesis spec. 1643 chaindb := MakeChainDatabase(ctx, stack, false) // TODO (MariusVanDerWijden) make this read only 1644 if rawdb.ReadCanonicalHash(chaindb, 0) != (common.Hash{}) { 1645 cfg.Genesis = nil // fallback to db content 1646 } 1647 chaindb.Close() 1648 } 1649 if !ctx.GlobalIsSet(MinerGasPriceFlag.Name) { 1650 cfg.Miner.GasPrice = big.NewInt(1) 1651 } 1652 default: 1653 if cfg.NetworkId == 1 { 1654 SetDNSDiscoveryDefaults(cfg, params.MainnetGenesisHash) 1655 } 1656 } 1657 } 1658 1659 // SetDNSDiscoveryDefaults configures DNS discovery with the given URL if 1660 // no URLs are set. 1661 func SetDNSDiscoveryDefaults(cfg *ethconfig.Config, genesis common.Hash) { 1662 if cfg.EthDiscoveryURLs != nil { 1663 return // already set through flags/config 1664 } 1665 protocol := "all" 1666 if cfg.SyncMode == downloader.LightSync { 1667 protocol = "les" 1668 } 1669 if url := params.KnownDNSNetwork(genesis, protocol); url != "" { 1670 cfg.EthDiscoveryURLs = []string{url} 1671 cfg.SnapDiscoveryURLs = cfg.EthDiscoveryURLs 1672 } 1673 } 1674 1675 // RegisterEthService adds an Ethereum client to the stack. 1676 // The second return value is the full node instance, which may be nil if the 1677 // node is running as a light client. 1678 func RegisterEthService(stack *node.Node, cfg *ethconfig.Config) (ethapi.Backend, *eth.Ethereum) { 1679 if cfg.SyncMode == downloader.LightSync { 1680 backend, err := les.New(stack, cfg) 1681 if err != nil { 1682 Fatalf("Failed to register the Ethereum service: %v", err) 1683 } 1684 stack.RegisterAPIs(tracers.APIs(backend.ApiBackend)) 1685 return backend.ApiBackend, nil 1686 } 1687 backend, err := eth.New(stack, cfg) 1688 if err != nil { 1689 Fatalf("Failed to register the Ethereum service: %v", err) 1690 } 1691 if cfg.LightServ > 0 { 1692 _, err := les.NewLesServer(stack, backend, cfg) 1693 if err != nil { 1694 Fatalf("Failed to create the LES server: %v", err) 1695 } 1696 } 1697 stack.RegisterAPIs(tracers.APIs(backend.APIBackend)) 1698 return backend.APIBackend, backend 1699 } 1700 1701 // RegisterEthStatsService configures the Ethereum Stats daemon and adds it to 1702 // the given node. 1703 func RegisterEthStatsService(stack *node.Node, backend ethapi.Backend, url string) { 1704 if err := ethstats.New(stack, backend, backend.Engine(), url); err != nil { 1705 Fatalf("Failed to register the Ethereum Stats service: %v", err) 1706 } 1707 } 1708 1709 // RegisterGraphQLService is a utility function to construct a new service and register it against a node. 1710 func RegisterGraphQLService(stack *node.Node, backend ethapi.Backend, cfg node.Config) { 1711 if err := graphql.New(stack, backend, cfg.GraphQLCors, cfg.GraphQLVirtualHosts); err != nil { 1712 Fatalf("Failed to register the GraphQL service: %v", err) 1713 } 1714 } 1715 1716 func SetupMetrics(ctx *cli.Context) { 1717 if metrics.Enabled { 1718 log.Info("Enabling metrics collection") 1719 1720 var ( 1721 enableExport = ctx.GlobalBool(MetricsEnableInfluxDBFlag.Name) 1722 enableExportV2 = ctx.GlobalBool(MetricsEnableInfluxDBV2Flag.Name) 1723 ) 1724 1725 if enableExport || enableExportV2 { 1726 CheckExclusive(ctx, MetricsEnableInfluxDBFlag, MetricsEnableInfluxDBV2Flag) 1727 1728 v1FlagIsSet := ctx.GlobalIsSet(MetricsInfluxDBUsernameFlag.Name) || 1729 ctx.GlobalIsSet(MetricsInfluxDBPasswordFlag.Name) 1730 1731 v2FlagIsSet := ctx.GlobalIsSet(MetricsInfluxDBTokenFlag.Name) || 1732 ctx.GlobalIsSet(MetricsInfluxDBOrganizationFlag.Name) || 1733 ctx.GlobalIsSet(MetricsInfluxDBBucketFlag.Name) 1734 1735 if enableExport && v2FlagIsSet { 1736 Fatalf("Flags --influxdb.metrics.organization, --influxdb.metrics.token, --influxdb.metrics.bucket are only available for influxdb-v2") 1737 } else if enableExportV2 && v1FlagIsSet { 1738 Fatalf("Flags --influxdb.metrics.username, --influxdb.metrics.password are only available for influxdb-v1") 1739 } 1740 } 1741 1742 var ( 1743 endpoint = ctx.GlobalString(MetricsInfluxDBEndpointFlag.Name) 1744 database = ctx.GlobalString(MetricsInfluxDBDatabaseFlag.Name) 1745 username = ctx.GlobalString(MetricsInfluxDBUsernameFlag.Name) 1746 password = ctx.GlobalString(MetricsInfluxDBPasswordFlag.Name) 1747 1748 token = ctx.GlobalString(MetricsInfluxDBTokenFlag.Name) 1749 bucket = ctx.GlobalString(MetricsInfluxDBBucketFlag.Name) 1750 organization = ctx.GlobalString(MetricsInfluxDBOrganizationFlag.Name) 1751 ) 1752 1753 if enableExport { 1754 tagsMap := SplitTagsFlag(ctx.GlobalString(MetricsInfluxDBTagsFlag.Name)) 1755 1756 log.Info("Enabling metrics export to InfluxDB") 1757 1758 go influxdb.InfluxDBWithTags(metrics.DefaultRegistry, 10*time.Second, endpoint, database, username, password, "geth.", tagsMap) 1759 } else if enableExportV2 { 1760 tagsMap := SplitTagsFlag(ctx.GlobalString(MetricsInfluxDBTagsFlag.Name)) 1761 1762 log.Info("Enabling metrics export to InfluxDB (v2)") 1763 1764 go influxdb.InfluxDBV2WithTags(metrics.DefaultRegistry, 10*time.Second, endpoint, token, bucket, organization, "geth.", tagsMap) 1765 } 1766 1767 if ctx.GlobalIsSet(MetricsHTTPFlag.Name) { 1768 address := fmt.Sprintf("%s:%d", ctx.GlobalString(MetricsHTTPFlag.Name), ctx.GlobalInt(MetricsPortFlag.Name)) 1769 log.Info("Enabling stand-alone metrics HTTP endpoint", "address", address) 1770 exp.Setup(address) 1771 } 1772 } 1773 } 1774 1775 func SplitTagsFlag(tagsFlag string) map[string]string { 1776 tags := strings.Split(tagsFlag, ",") 1777 tagsMap := map[string]string{} 1778 1779 for _, t := range tags { 1780 if t != "" { 1781 kv := strings.Split(t, "=") 1782 1783 if len(kv) == 2 { 1784 tagsMap[kv[0]] = kv[1] 1785 } 1786 } 1787 } 1788 1789 return tagsMap 1790 } 1791 1792 // MakeChainDatabase open an LevelDB using the flags passed to the client and will hard crash if it fails. 1793 func MakeChainDatabase(ctx *cli.Context, stack *node.Node, readonly bool) ethdb.Database { 1794 var ( 1795 cache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheDatabaseFlag.Name) / 100 1796 handles = MakeDatabaseHandles() 1797 1798 err error 1799 chainDb ethdb.Database 1800 ) 1801 if ctx.GlobalString(SyncModeFlag.Name) == "light" { 1802 name := "lightchaindata" 1803 chainDb, err = stack.OpenDatabase(name, cache, handles, "", readonly) 1804 } else { 1805 name := "chaindata" 1806 chainDb, err = stack.OpenDatabaseWithFreezer(name, cache, handles, ctx.GlobalString(AncientFlag.Name), "", readonly) 1807 } 1808 if err != nil { 1809 Fatalf("Could not open database: %v", err) 1810 } 1811 return chainDb 1812 } 1813 1814 func MakeGenesis(ctx *cli.Context) *core.Genesis { 1815 var genesis *core.Genesis 1816 switch { 1817 case ctx.GlobalBool(MainnetFlag.Name): 1818 genesis = core.DefaultGenesisBlock() 1819 case ctx.GlobalBool(RopstenFlag.Name): 1820 genesis = core.DefaultRopstenGenesisBlock() 1821 case ctx.GlobalBool(RinkebyFlag.Name): 1822 genesis = core.DefaultRinkebyGenesisBlock() 1823 case ctx.GlobalBool(GoerliFlag.Name): 1824 genesis = core.DefaultGoerliGenesisBlock() 1825 case ctx.GlobalBool(DeveloperFlag.Name): 1826 Fatalf("Developer chains are ephemeral") 1827 } 1828 return genesis 1829 } 1830 1831 // MakeChain creates a chain manager from set command line flags. 1832 func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chainDb ethdb.Database) { 1833 var err error 1834 chainDb = MakeChainDatabase(ctx, stack, false) // TODO(rjl493456442) support read-only database 1835 config, _, err := core.SetupGenesisBlock(chainDb, MakeGenesis(ctx)) 1836 if err != nil { 1837 Fatalf("%v", err) 1838 } 1839 var engine consensus.Engine 1840 if config.Clique != nil { 1841 engine = clique.New(config.Clique, chainDb) 1842 } else { 1843 engine = ethash.NewFaker() 1844 if !ctx.GlobalBool(FakePoWFlag.Name) { 1845 engine = ethash.New(ethash.Config{ 1846 CacheDir: stack.ResolvePath(ethconfig.Defaults.Ethash.CacheDir), 1847 CachesInMem: ethconfig.Defaults.Ethash.CachesInMem, 1848 CachesOnDisk: ethconfig.Defaults.Ethash.CachesOnDisk, 1849 CachesLockMmap: ethconfig.Defaults.Ethash.CachesLockMmap, 1850 DatasetDir: stack.ResolvePath(ethconfig.Defaults.Ethash.DatasetDir), 1851 DatasetsInMem: ethconfig.Defaults.Ethash.DatasetsInMem, 1852 DatasetsOnDisk: ethconfig.Defaults.Ethash.DatasetsOnDisk, 1853 DatasetsLockMmap: ethconfig.Defaults.Ethash.DatasetsLockMmap, 1854 }, nil, false) 1855 } 1856 } 1857 if gcmode := ctx.GlobalString(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" { 1858 Fatalf("--%s must be either 'full' or 'archive'", GCModeFlag.Name) 1859 } 1860 cache := &core.CacheConfig{ 1861 TrieCleanLimit: ethconfig.Defaults.TrieCleanCache, 1862 TrieCleanNoPrefetch: ctx.GlobalBool(CacheNoPrefetchFlag.Name), 1863 TrieDirtyLimit: ethconfig.Defaults.TrieDirtyCache, 1864 TrieDirtyDisabled: ctx.GlobalString(GCModeFlag.Name) == "archive", 1865 TrieTimeLimit: ethconfig.Defaults.TrieTimeout, 1866 SnapshotLimit: ethconfig.Defaults.SnapshotCache, 1867 Preimages: ctx.GlobalBool(CachePreimagesFlag.Name), 1868 } 1869 if cache.TrieDirtyDisabled && !cache.Preimages { 1870 cache.Preimages = true 1871 log.Info("Enabling recording of key preimages since archive mode is used") 1872 } 1873 if !ctx.GlobalBool(SnapshotFlag.Name) { 1874 cache.SnapshotLimit = 0 // Disabled 1875 } 1876 if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheTrieFlag.Name) { 1877 cache.TrieCleanLimit = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheTrieFlag.Name) / 100 1878 } 1879 if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheGCFlag.Name) { 1880 cache.TrieDirtyLimit = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheGCFlag.Name) / 100 1881 } 1882 vmcfg := vm.Config{EnablePreimageRecording: ctx.GlobalBool(VMEnableDebugFlag.Name)} 1883 1884 // TODO(rjl493456442) disable snapshot generation/wiping if the chain is read only. 1885 // Disable transaction indexing/unindexing by default. 1886 chain, err = core.NewBlockChain(chainDb, cache, config, engine, vmcfg, nil, nil) 1887 if err != nil { 1888 Fatalf("Can't create BlockChain: %v", err) 1889 } 1890 return chain, chainDb 1891 } 1892 1893 // MakeConsolePreloads retrieves the absolute paths for the console JavaScript 1894 // scripts to preload before starting. 1895 func MakeConsolePreloads(ctx *cli.Context) []string { 1896 // Skip preloading if there's nothing to preload 1897 if ctx.GlobalString(PreloadJSFlag.Name) == "" { 1898 return nil 1899 } 1900 // Otherwise resolve absolute paths and return them 1901 var preloads []string 1902 1903 for _, file := range strings.Split(ctx.GlobalString(PreloadJSFlag.Name), ",") { 1904 preloads = append(preloads, strings.TrimSpace(file)) 1905 } 1906 return preloads 1907 } 1908 1909 // MigrateFlags sets the global flag from a local flag when it's set. 1910 // This is a temporary function used for migrating old command/flags to the 1911 // new format. 1912 // 1913 // e.g. geth account new --keystore /tmp/mykeystore --lightkdf 1914 // 1915 // is equivalent after calling this method with: 1916 // 1917 // geth --keystore /tmp/mykeystore --lightkdf account new 1918 // 1919 // This allows the use of the existing configuration functionality. 1920 // When all flags are migrated this function can be removed and the existing 1921 // configuration functionality must be changed that is uses local flags 1922 func MigrateFlags(action func(ctx *cli.Context) error) func(*cli.Context) error { 1923 return func(ctx *cli.Context) error { 1924 for _, name := range ctx.FlagNames() { 1925 if ctx.IsSet(name) { 1926 ctx.GlobalSet(name, ctx.String(name)) 1927 } 1928 } 1929 return action(ctx) 1930 } 1931 }