github.com/aidoskuneen/adk-node@v0.0.0-20220315131952-2e32567cb7f4/cmd/utils/flags.go (about) 1 // Copyright 2021 The adkgo Authors 2 // This file is part of adkgo. 3 // 4 // adkgo 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 // adkgo 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 adkgo. If not, see <http://www.gnu.org/licenses/>. 16 17 // Package utils contains internal helper functions for adkgo 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/aidoskuneen/adk-node/accounts" 37 "github.com/aidoskuneen/adk-node/accounts/keystore" 38 "github.com/aidoskuneen/adk-node/common" 39 "github.com/aidoskuneen/adk-node/common/fdlimit" 40 "github.com/aidoskuneen/adk-node/consensus" 41 "github.com/aidoskuneen/adk-node/consensus/clique" 42 "github.com/aidoskuneen/adk-node/consensus/ethash" 43 "github.com/aidoskuneen/adk-node/core" 44 "github.com/aidoskuneen/adk-node/core/rawdb" 45 "github.com/aidoskuneen/adk-node/core/vm" 46 "github.com/aidoskuneen/adk-node/crypto" 47 "github.com/aidoskuneen/adk-node/eth" 48 "github.com/aidoskuneen/adk-node/eth/downloader" 49 "github.com/aidoskuneen/adk-node/eth/ethconfig" 50 "github.com/aidoskuneen/adk-node/eth/gasprice" 51 "github.com/aidoskuneen/adk-node/eth/tracers" 52 "github.com/aidoskuneen/adk-node/ethdb" 53 "github.com/aidoskuneen/adk-node/ethstats" 54 "github.com/aidoskuneen/adk-node/graphql" 55 "github.com/aidoskuneen/adk-node/internal/ethapi" 56 "github.com/aidoskuneen/adk-node/internal/flags" 57 "github.com/aidoskuneen/adk-node/les" 58 "github.com/aidoskuneen/adk-node/log" 59 "github.com/aidoskuneen/adk-node/metrics" 60 "github.com/aidoskuneen/adk-node/metrics/exp" 61 "github.com/aidoskuneen/adk-node/metrics/influxdb" 62 "github.com/aidoskuneen/adk-node/miner" 63 "github.com/aidoskuneen/adk-node/node" 64 "github.com/aidoskuneen/adk-node/p2p" 65 "github.com/aidoskuneen/adk-node/p2p/enode" 66 "github.com/aidoskuneen/adk-node/p2p/nat" 67 "github.com/aidoskuneen/adk-node/p2p/netutil" 68 "github.com/aidoskuneen/adk-node/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 MinerNoVerfiyFlag = 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(LegacyRPCEnabledFlag.Name) && cfg.HTTPHost == "" { 924 log.Warn("The flag --rpc is deprecated and will be removed June 2021, please use --http") 925 cfg.HTTPHost = "127.0.0.1" 926 if ctx.GlobalIsSet(LegacyRPCListenAddrFlag.Name) { 927 cfg.HTTPHost = ctx.GlobalString(LegacyRPCListenAddrFlag.Name) 928 log.Warn("The flag --rpcaddr is deprecated and will be removed June 2021, please use --http.addr") 929 } 930 } 931 if ctx.GlobalBool(HTTPEnabledFlag.Name) && cfg.HTTPHost == "" { 932 cfg.HTTPHost = "127.0.0.1" 933 if ctx.GlobalIsSet(HTTPListenAddrFlag.Name) { 934 cfg.HTTPHost = ctx.GlobalString(HTTPListenAddrFlag.Name) 935 } 936 } 937 938 if ctx.GlobalIsSet(LegacyRPCPortFlag.Name) { 939 cfg.HTTPPort = ctx.GlobalInt(LegacyRPCPortFlag.Name) 940 log.Warn("The flag --rpcport is deprecated and will be removed June 2021, please use --http.port") 941 } 942 if ctx.GlobalIsSet(HTTPPortFlag.Name) { 943 cfg.HTTPPort = ctx.GlobalInt(HTTPPortFlag.Name) 944 } 945 946 if ctx.GlobalIsSet(LegacyRPCCORSDomainFlag.Name) { 947 cfg.HTTPCors = SplitAndTrim(ctx.GlobalString(LegacyRPCCORSDomainFlag.Name)) 948 log.Warn("The flag --rpccorsdomain is deprecated and will be removed June 2021, please use --http.corsdomain") 949 } 950 if ctx.GlobalIsSet(HTTPCORSDomainFlag.Name) { 951 cfg.HTTPCors = SplitAndTrim(ctx.GlobalString(HTTPCORSDomainFlag.Name)) 952 } 953 954 if ctx.GlobalIsSet(LegacyRPCApiFlag.Name) { 955 cfg.HTTPModules = SplitAndTrim(ctx.GlobalString(LegacyRPCApiFlag.Name)) 956 log.Warn("The flag --rpcapi is deprecated and will be removed June 2021, please use --http.api") 957 } 958 if ctx.GlobalIsSet(HTTPApiFlag.Name) { 959 cfg.HTTPModules = SplitAndTrim(ctx.GlobalString(HTTPApiFlag.Name)) 960 } 961 962 if ctx.GlobalIsSet(LegacyRPCVirtualHostsFlag.Name) { 963 cfg.HTTPVirtualHosts = SplitAndTrim(ctx.GlobalString(LegacyRPCVirtualHostsFlag.Name)) 964 log.Warn("The flag --rpcvhosts is deprecated and will be removed June 2021, please use --http.vhosts") 965 } 966 if ctx.GlobalIsSet(HTTPVirtualHostsFlag.Name) { 967 cfg.HTTPVirtualHosts = SplitAndTrim(ctx.GlobalString(HTTPVirtualHostsFlag.Name)) 968 } 969 970 if ctx.GlobalIsSet(HTTPPathPrefixFlag.Name) { 971 cfg.HTTPPathPrefix = ctx.GlobalString(HTTPPathPrefixFlag.Name) 972 } 973 if ctx.GlobalIsSet(AllowUnprotectedTxs.Name) { 974 cfg.AllowUnprotectedTxs = ctx.GlobalBool(AllowUnprotectedTxs.Name) 975 } 976 } 977 978 // setGraphQL creates the GraphQL listener interface string from the set 979 // command line flags, returning empty if the GraphQL endpoint is disabled. 980 func setGraphQL(ctx *cli.Context, cfg *node.Config) { 981 if ctx.GlobalIsSet(GraphQLCORSDomainFlag.Name) { 982 cfg.GraphQLCors = SplitAndTrim(ctx.GlobalString(GraphQLCORSDomainFlag.Name)) 983 } 984 if ctx.GlobalIsSet(GraphQLVirtualHostsFlag.Name) { 985 cfg.GraphQLVirtualHosts = SplitAndTrim(ctx.GlobalString(GraphQLVirtualHostsFlag.Name)) 986 } 987 } 988 989 // setWS creates the WebSocket RPC listener interface string from the set 990 // command line flags, returning empty if the HTTP endpoint is disabled. 991 func setWS(ctx *cli.Context, cfg *node.Config) { 992 if ctx.GlobalBool(WSEnabledFlag.Name) && cfg.WSHost == "" { 993 cfg.WSHost = "127.0.0.1" 994 if ctx.GlobalIsSet(WSListenAddrFlag.Name) { 995 cfg.WSHost = ctx.GlobalString(WSListenAddrFlag.Name) 996 } 997 } 998 if ctx.GlobalIsSet(WSPortFlag.Name) { 999 cfg.WSPort = ctx.GlobalInt(WSPortFlag.Name) 1000 } 1001 1002 if ctx.GlobalIsSet(WSAllowedOriginsFlag.Name) { 1003 cfg.WSOrigins = SplitAndTrim(ctx.GlobalString(WSAllowedOriginsFlag.Name)) 1004 } 1005 1006 if ctx.GlobalIsSet(WSApiFlag.Name) { 1007 cfg.WSModules = SplitAndTrim(ctx.GlobalString(WSApiFlag.Name)) 1008 } 1009 1010 if ctx.GlobalIsSet(WSPathPrefixFlag.Name) { 1011 cfg.WSPathPrefix = ctx.GlobalString(WSPathPrefixFlag.Name) 1012 } 1013 } 1014 1015 // setIPC creates an IPC path configuration from the set command line flags, 1016 // returning an empty string if IPC was explicitly disabled, or the set path. 1017 func setIPC(ctx *cli.Context, cfg *node.Config) { 1018 CheckExclusive(ctx, IPCDisabledFlag, IPCPathFlag) 1019 switch { 1020 case ctx.GlobalBool(IPCDisabledFlag.Name): 1021 cfg.IPCPath = "" 1022 case ctx.GlobalIsSet(IPCPathFlag.Name): 1023 cfg.IPCPath = ctx.GlobalString(IPCPathFlag.Name) 1024 } 1025 } 1026 1027 // setLes configures the les server and ultra light client settings from the command line flags. 1028 func setLes(ctx *cli.Context, cfg *ethconfig.Config) { 1029 if ctx.GlobalIsSet(LightServeFlag.Name) { 1030 cfg.LightServ = ctx.GlobalInt(LightServeFlag.Name) 1031 } 1032 if ctx.GlobalIsSet(LightIngressFlag.Name) { 1033 cfg.LightIngress = ctx.GlobalInt(LightIngressFlag.Name) 1034 } 1035 if ctx.GlobalIsSet(LightEgressFlag.Name) { 1036 cfg.LightEgress = ctx.GlobalInt(LightEgressFlag.Name) 1037 } 1038 if ctx.GlobalIsSet(LightMaxPeersFlag.Name) { 1039 cfg.LightPeers = ctx.GlobalInt(LightMaxPeersFlag.Name) 1040 } 1041 if ctx.GlobalIsSet(UltraLightServersFlag.Name) { 1042 cfg.UltraLightServers = strings.Split(ctx.GlobalString(UltraLightServersFlag.Name), ",") 1043 } 1044 if ctx.GlobalIsSet(UltraLightFractionFlag.Name) { 1045 cfg.UltraLightFraction = ctx.GlobalInt(UltraLightFractionFlag.Name) 1046 } 1047 if cfg.UltraLightFraction <= 0 && cfg.UltraLightFraction > 100 { 1048 log.Error("Ultra light fraction is invalid", "had", cfg.UltraLightFraction, "updated", ethconfig.Defaults.UltraLightFraction) 1049 cfg.UltraLightFraction = ethconfig.Defaults.UltraLightFraction 1050 } 1051 if ctx.GlobalIsSet(UltraLightOnlyAnnounceFlag.Name) { 1052 cfg.UltraLightOnlyAnnounce = ctx.GlobalBool(UltraLightOnlyAnnounceFlag.Name) 1053 } 1054 if ctx.GlobalIsSet(LightNoPruneFlag.Name) { 1055 cfg.LightNoPrune = ctx.GlobalBool(LightNoPruneFlag.Name) 1056 } 1057 if ctx.GlobalIsSet(LightNoSyncServeFlag.Name) { 1058 cfg.LightNoSyncServe = ctx.GlobalBool(LightNoSyncServeFlag.Name) 1059 } 1060 } 1061 1062 // MakeDatabaseHandles raises out the number of allowed file handles per process 1063 // for Geth and returns half of the allowance to assign to the database. 1064 func MakeDatabaseHandles() int { 1065 limit, err := fdlimit.Maximum() 1066 if err != nil { 1067 Fatalf("Failed to retrieve file descriptor allowance: %v", err) 1068 } 1069 raised, err := fdlimit.Raise(uint64(limit)) 1070 if err != nil { 1071 Fatalf("Failed to raise file descriptor allowance: %v", err) 1072 } 1073 return int(raised / 2) // Leave half for networking and other stuff 1074 } 1075 1076 // MakeAddress converts an account specified directly as a hex encoded string or 1077 // a key index in the key store to an internal account representation. 1078 func MakeAddress(ks *keystore.KeyStore, account string) (accounts.Account, error) { 1079 // If the specified account is a valid address, return it 1080 if common.IsHexAddress(account) { 1081 return accounts.Account{Address: common.HexToAddress(account)}, nil 1082 } 1083 // Otherwise try to interpret the account as a keystore index 1084 index, err := strconv.Atoi(account) 1085 if err != nil || index < 0 { 1086 return accounts.Account{}, fmt.Errorf("invalid account address or index %q", account) 1087 } 1088 log.Warn("-------------------------------------------------------------------") 1089 log.Warn("Referring to accounts by order in the keystore folder is dangerous!") 1090 log.Warn("This functionality is deprecated and will be removed in the future!") 1091 log.Warn("Please use explicit addresses! (can search via `geth account list`)") 1092 log.Warn("-------------------------------------------------------------------") 1093 1094 accs := ks.Accounts() 1095 if len(accs) <= index { 1096 return accounts.Account{}, fmt.Errorf("index %d higher than number of accounts %d", index, len(accs)) 1097 } 1098 return accs[index], nil 1099 } 1100 1101 // setEtherbase retrieves the etherbase either from the directly specified 1102 // command line flags or from the keystore if CLI indexed. 1103 func setEtherbase(ctx *cli.Context, ks *keystore.KeyStore, cfg *ethconfig.Config) { 1104 // Extract the current etherbase 1105 var etherbase string 1106 if ctx.GlobalIsSet(MinerEtherbaseFlag.Name) { 1107 etherbase = ctx.GlobalString(MinerEtherbaseFlag.Name) 1108 } 1109 // Convert the etherbase into an address and configure it 1110 if etherbase != "" { 1111 if ks != nil { 1112 account, err := MakeAddress(ks, etherbase) 1113 if err != nil { 1114 Fatalf("Invalid miner etherbase: %v", err) 1115 } 1116 cfg.Miner.Etherbase = account.Address 1117 } else { 1118 Fatalf("No etherbase configured") 1119 } 1120 } 1121 } 1122 1123 // MakePasswordList reads password lines from the file specified by the global --password flag. 1124 func MakePasswordList(ctx *cli.Context) []string { 1125 path := ctx.GlobalString(PasswordFileFlag.Name) 1126 if path == "" { 1127 return nil 1128 } 1129 text, err := ioutil.ReadFile(path) 1130 if err != nil { 1131 Fatalf("Failed to read password file: %v", err) 1132 } 1133 lines := strings.Split(string(text), "\n") 1134 // Sanitise DOS line endings. 1135 for i := range lines { 1136 lines[i] = strings.TrimRight(lines[i], "\r") 1137 } 1138 return lines 1139 } 1140 1141 func SetP2PConfig(ctx *cli.Context, cfg *p2p.Config) { 1142 setNodeKey(ctx, cfg) 1143 setNAT(ctx, cfg) 1144 setListenAddress(ctx, cfg) 1145 setBootstrapNodes(ctx, cfg) 1146 setBootstrapNodesV5(ctx, cfg) 1147 1148 lightClient := ctx.GlobalString(SyncModeFlag.Name) == "light" 1149 lightServer := (ctx.GlobalInt(LightServeFlag.Name) != 0) 1150 1151 lightPeers := ctx.GlobalInt(LightMaxPeersFlag.Name) 1152 if lightClient && !ctx.GlobalIsSet(LightMaxPeersFlag.Name) { 1153 // dynamic default - for clients we use 1/10th of the default for servers 1154 lightPeers /= 10 1155 } 1156 1157 if ctx.GlobalIsSet(MaxPeersFlag.Name) { 1158 cfg.MaxPeers = ctx.GlobalInt(MaxPeersFlag.Name) 1159 if lightServer && !ctx.GlobalIsSet(LightMaxPeersFlag.Name) { 1160 cfg.MaxPeers += lightPeers 1161 } 1162 } else { 1163 if lightServer { 1164 cfg.MaxPeers += lightPeers 1165 } 1166 if lightClient && ctx.GlobalIsSet(LightMaxPeersFlag.Name) && cfg.MaxPeers < lightPeers { 1167 cfg.MaxPeers = lightPeers 1168 } 1169 } 1170 if !(lightClient || lightServer) { 1171 lightPeers = 0 1172 } 1173 ethPeers := cfg.MaxPeers - lightPeers 1174 if lightClient { 1175 ethPeers = 0 1176 } 1177 log.Info("Maximum peer count", "ETH", ethPeers, "LES", lightPeers, "total", cfg.MaxPeers) 1178 1179 if ctx.GlobalIsSet(MaxPendingPeersFlag.Name) { 1180 cfg.MaxPendingPeers = ctx.GlobalInt(MaxPendingPeersFlag.Name) 1181 } 1182 if ctx.GlobalIsSet(NoDiscoverFlag.Name) || lightClient { 1183 cfg.NoDiscovery = true 1184 } 1185 1186 // if we're running a light client or server, force enable the v5 peer discovery 1187 // unless it is explicitly disabled with --nodiscover note that explicitly specifying 1188 // --v5disc overrides --nodiscover, in which case the later only disables v4 discovery 1189 forceV5Discovery := (lightClient || lightServer) && !ctx.GlobalBool(NoDiscoverFlag.Name) 1190 if ctx.GlobalIsSet(DiscoveryV5Flag.Name) { 1191 cfg.DiscoveryV5 = ctx.GlobalBool(DiscoveryV5Flag.Name) 1192 } else if forceV5Discovery { 1193 cfg.DiscoveryV5 = true 1194 } 1195 1196 if netrestrict := ctx.GlobalString(NetrestrictFlag.Name); netrestrict != "" { 1197 list, err := netutil.ParseNetlist(netrestrict) 1198 if err != nil { 1199 Fatalf("Option %q: %v", NetrestrictFlag.Name, err) 1200 } 1201 cfg.NetRestrict = list 1202 } 1203 1204 if ctx.GlobalBool(DeveloperFlag.Name) || ctx.GlobalBool(CatalystFlag.Name) { 1205 // --dev mode can't use p2p networking. 1206 cfg.MaxPeers = 0 1207 cfg.ListenAddr = "" 1208 cfg.NoDial = true 1209 cfg.NoDiscovery = true 1210 cfg.DiscoveryV5 = false 1211 } 1212 } 1213 1214 // SetNodeConfig applies node-related command line flags to the config. 1215 func SetNodeConfig(ctx *cli.Context, cfg *node.Config) { 1216 SetP2PConfig(ctx, &cfg.P2P) 1217 setIPC(ctx, cfg) 1218 setHTTP(ctx, cfg) 1219 setGraphQL(ctx, cfg) 1220 setWS(ctx, cfg) 1221 setNodeUserIdent(ctx, cfg) 1222 setDataDir(ctx, cfg) 1223 setSmartCard(ctx, cfg) 1224 1225 if ctx.GlobalIsSet(ExternalSignerFlag.Name) { 1226 cfg.ExternalSigner = ctx.GlobalString(ExternalSignerFlag.Name) 1227 } 1228 1229 if ctx.GlobalIsSet(KeyStoreDirFlag.Name) { 1230 cfg.KeyStoreDir = ctx.GlobalString(KeyStoreDirFlag.Name) 1231 } 1232 if ctx.GlobalIsSet(DeveloperFlag.Name) { 1233 cfg.UseLightweightKDF = true 1234 } 1235 if ctx.GlobalIsSet(LightKDFFlag.Name) { 1236 cfg.UseLightweightKDF = ctx.GlobalBool(LightKDFFlag.Name) 1237 } 1238 if ctx.GlobalIsSet(NoUSBFlag.Name) || cfg.NoUSB { 1239 log.Warn("Option nousb is deprecated and USB is deactivated by default. Use --usb to enable") 1240 } 1241 if ctx.GlobalIsSet(USBFlag.Name) { 1242 cfg.USB = ctx.GlobalBool(USBFlag.Name) 1243 } 1244 if ctx.GlobalIsSet(InsecureUnlockAllowedFlag.Name) { 1245 cfg.InsecureUnlockAllowed = ctx.GlobalBool(InsecureUnlockAllowedFlag.Name) 1246 } 1247 } 1248 1249 func setSmartCard(ctx *cli.Context, cfg *node.Config) { 1250 // Skip enabling smartcards if no path is set 1251 path := ctx.GlobalString(SmartCardDaemonPathFlag.Name) 1252 if path == "" { 1253 return 1254 } 1255 // Sanity check that the smartcard path is valid 1256 fi, err := os.Stat(path) 1257 if err != nil { 1258 log.Info("Smartcard socket not found, disabling", "err", err) 1259 return 1260 } 1261 if fi.Mode()&os.ModeType != os.ModeSocket { 1262 log.Error("Invalid smartcard daemon path", "path", path, "type", fi.Mode().String()) 1263 return 1264 } 1265 // Smartcard daemon path exists and is a socket, enable it 1266 cfg.SmartCardDaemonPath = path 1267 } 1268 1269 func setDataDir(ctx *cli.Context, cfg *node.Config) { 1270 switch { 1271 case ctx.GlobalIsSet(DataDirFlag.Name): 1272 cfg.DataDir = ctx.GlobalString(DataDirFlag.Name) 1273 case ctx.GlobalBool(DeveloperFlag.Name): 1274 cfg.DataDir = "" // unless explicitly requested, use memory databases 1275 case ctx.GlobalBool(RopstenFlag.Name) && cfg.DataDir == node.DefaultDataDir(): 1276 // Maintain compatibility with older Geth configurations storing the 1277 // Ropsten database in `testnet` instead of `ropsten`. 1278 legacyPath := filepath.Join(node.DefaultDataDir(), "testnet") 1279 if _, err := os.Stat(legacyPath); !os.IsNotExist(err) { 1280 log.Warn("Using the deprecated `testnet` datadir. Future versions will store the Ropsten chain in `ropsten`.") 1281 cfg.DataDir = legacyPath 1282 } else { 1283 cfg.DataDir = filepath.Join(node.DefaultDataDir(), "ropsten") 1284 } 1285 1286 cfg.DataDir = filepath.Join(node.DefaultDataDir(), "ropsten") 1287 case ctx.GlobalBool(RinkebyFlag.Name) && cfg.DataDir == node.DefaultDataDir(): 1288 cfg.DataDir = filepath.Join(node.DefaultDataDir(), "rinkeby") 1289 case ctx.GlobalBool(GoerliFlag.Name) && cfg.DataDir == node.DefaultDataDir(): 1290 cfg.DataDir = filepath.Join(node.DefaultDataDir(), "goerli") 1291 } 1292 } 1293 1294 func setGPO(ctx *cli.Context, cfg *gasprice.Config, light bool) { 1295 // If we are running the light client, apply another group 1296 // settings for gas oracle. 1297 if light { 1298 *cfg = ethconfig.LightClientGPO 1299 } 1300 if ctx.GlobalIsSet(GpoBlocksFlag.Name) { 1301 cfg.Blocks = ctx.GlobalInt(GpoBlocksFlag.Name) 1302 } 1303 if ctx.GlobalIsSet(GpoPercentileFlag.Name) { 1304 cfg.Percentile = ctx.GlobalInt(GpoPercentileFlag.Name) 1305 } 1306 if ctx.GlobalIsSet(GpoMaxGasPriceFlag.Name) { 1307 cfg.MaxPrice = big.NewInt(ctx.GlobalInt64(GpoMaxGasPriceFlag.Name)) 1308 } 1309 if ctx.GlobalIsSet(GpoIgnoreGasPriceFlag.Name) { 1310 cfg.IgnorePrice = big.NewInt(ctx.GlobalInt64(GpoIgnoreGasPriceFlag.Name)) 1311 } 1312 } 1313 1314 func setTxPool(ctx *cli.Context, cfg *core.TxPoolConfig) { 1315 if ctx.GlobalIsSet(TxPoolLocalsFlag.Name) { 1316 locals := strings.Split(ctx.GlobalString(TxPoolLocalsFlag.Name), ",") 1317 for _, account := range locals { 1318 if trimmed := strings.TrimSpace(account); !common.IsHexAddress(trimmed) { 1319 Fatalf("Invalid account in --txpool.locals: %s", trimmed) 1320 } else { 1321 cfg.Locals = append(cfg.Locals, common.HexToAddress(account)) 1322 } 1323 } 1324 } 1325 if ctx.GlobalIsSet(TxPoolNoLocalsFlag.Name) { 1326 cfg.NoLocals = ctx.GlobalBool(TxPoolNoLocalsFlag.Name) 1327 } 1328 if ctx.GlobalIsSet(TxPoolJournalFlag.Name) { 1329 cfg.Journal = ctx.GlobalString(TxPoolJournalFlag.Name) 1330 } 1331 if ctx.GlobalIsSet(TxPoolRejournalFlag.Name) { 1332 cfg.Rejournal = ctx.GlobalDuration(TxPoolRejournalFlag.Name) 1333 } 1334 if ctx.GlobalIsSet(TxPoolPriceLimitFlag.Name) { 1335 cfg.PriceLimit = ctx.GlobalUint64(TxPoolPriceLimitFlag.Name) 1336 } 1337 if ctx.GlobalIsSet(TxPoolPriceBumpFlag.Name) { 1338 cfg.PriceBump = ctx.GlobalUint64(TxPoolPriceBumpFlag.Name) 1339 } 1340 if ctx.GlobalIsSet(TxPoolAccountSlotsFlag.Name) { 1341 cfg.AccountSlots = ctx.GlobalUint64(TxPoolAccountSlotsFlag.Name) 1342 } 1343 if ctx.GlobalIsSet(TxPoolGlobalSlotsFlag.Name) { 1344 cfg.GlobalSlots = ctx.GlobalUint64(TxPoolGlobalSlotsFlag.Name) 1345 } 1346 if ctx.GlobalIsSet(TxPoolAccountQueueFlag.Name) { 1347 cfg.AccountQueue = ctx.GlobalUint64(TxPoolAccountQueueFlag.Name) 1348 } 1349 if ctx.GlobalIsSet(TxPoolGlobalQueueFlag.Name) { 1350 cfg.GlobalQueue = ctx.GlobalUint64(TxPoolGlobalQueueFlag.Name) 1351 } 1352 if ctx.GlobalIsSet(TxPoolLifetimeFlag.Name) { 1353 cfg.Lifetime = ctx.GlobalDuration(TxPoolLifetimeFlag.Name) 1354 } 1355 } 1356 1357 func setEthash(ctx *cli.Context, cfg *ethconfig.Config) { 1358 if ctx.GlobalIsSet(EthashCacheDirFlag.Name) { 1359 cfg.Ethash.CacheDir = ctx.GlobalString(EthashCacheDirFlag.Name) 1360 } 1361 if ctx.GlobalIsSet(EthashDatasetDirFlag.Name) { 1362 cfg.Ethash.DatasetDir = ctx.GlobalString(EthashDatasetDirFlag.Name) 1363 } 1364 if ctx.GlobalIsSet(EthashCachesInMemoryFlag.Name) { 1365 cfg.Ethash.CachesInMem = ctx.GlobalInt(EthashCachesInMemoryFlag.Name) 1366 } 1367 if ctx.GlobalIsSet(EthashCachesOnDiskFlag.Name) { 1368 cfg.Ethash.CachesOnDisk = ctx.GlobalInt(EthashCachesOnDiskFlag.Name) 1369 } 1370 if ctx.GlobalIsSet(EthashCachesLockMmapFlag.Name) { 1371 cfg.Ethash.CachesLockMmap = ctx.GlobalBool(EthashCachesLockMmapFlag.Name) 1372 } 1373 if ctx.GlobalIsSet(EthashDatasetsInMemoryFlag.Name) { 1374 cfg.Ethash.DatasetsInMem = ctx.GlobalInt(EthashDatasetsInMemoryFlag.Name) 1375 } 1376 if ctx.GlobalIsSet(EthashDatasetsOnDiskFlag.Name) { 1377 cfg.Ethash.DatasetsOnDisk = ctx.GlobalInt(EthashDatasetsOnDiskFlag.Name) 1378 } 1379 if ctx.GlobalIsSet(EthashDatasetsLockMmapFlag.Name) { 1380 cfg.Ethash.DatasetsLockMmap = ctx.GlobalBool(EthashDatasetsLockMmapFlag.Name) 1381 } 1382 } 1383 1384 func setMiner(ctx *cli.Context, cfg *miner.Config) { 1385 if ctx.GlobalIsSet(MinerNotifyFlag.Name) { 1386 cfg.Notify = strings.Split(ctx.GlobalString(MinerNotifyFlag.Name), ",") 1387 } 1388 cfg.NotifyFull = ctx.GlobalBool(MinerNotifyFullFlag.Name) 1389 if ctx.GlobalIsSet(MinerExtraDataFlag.Name) { 1390 cfg.ExtraData = []byte(ctx.GlobalString(MinerExtraDataFlag.Name)) 1391 } 1392 if ctx.GlobalIsSet(MinerGasLimitFlag.Name) { 1393 cfg.GasCeil = ctx.GlobalUint64(MinerGasLimitFlag.Name) 1394 } 1395 if ctx.GlobalIsSet(MinerGasPriceFlag.Name) { 1396 cfg.GasPrice = GlobalBig(ctx, MinerGasPriceFlag.Name) 1397 } 1398 if ctx.GlobalIsSet(MinerRecommitIntervalFlag.Name) { 1399 cfg.Recommit = ctx.GlobalDuration(MinerRecommitIntervalFlag.Name) 1400 } 1401 if ctx.GlobalIsSet(MinerNoVerfiyFlag.Name) { 1402 cfg.Noverify = ctx.GlobalBool(MinerNoVerfiyFlag.Name) 1403 } 1404 if ctx.GlobalIsSet(LegacyMinerGasTargetFlag.Name) { 1405 log.Warn("The generic --miner.gastarget flag is deprecated and will be removed in the future!") 1406 } 1407 } 1408 1409 func setWhitelist(ctx *cli.Context, cfg *ethconfig.Config) { 1410 whitelist := ctx.GlobalString(WhitelistFlag.Name) 1411 if whitelist == "" { 1412 return 1413 } 1414 cfg.Whitelist = make(map[uint64]common.Hash) 1415 for _, entry := range strings.Split(whitelist, ",") { 1416 parts := strings.Split(entry, "=") 1417 if len(parts) != 2 { 1418 Fatalf("Invalid whitelist entry: %s", entry) 1419 } 1420 number, err := strconv.ParseUint(parts[0], 0, 64) 1421 if err != nil { 1422 Fatalf("Invalid whitelist block number %s: %v", parts[0], err) 1423 } 1424 var hash common.Hash 1425 if err = hash.UnmarshalText([]byte(parts[1])); err != nil { 1426 Fatalf("Invalid whitelist hash %s: %v", parts[1], err) 1427 } 1428 cfg.Whitelist[number] = hash 1429 } 1430 } 1431 1432 // CheckExclusive verifies that only a single instance of the provided flags was 1433 // set by the user. Each flag might optionally be followed by a string type to 1434 // specialize it further. 1435 func CheckExclusive(ctx *cli.Context, args ...interface{}) { 1436 set := make([]string, 0, 1) 1437 for i := 0; i < len(args); i++ { 1438 // Make sure the next argument is a flag and skip if not set 1439 flag, ok := args[i].(cli.Flag) 1440 if !ok { 1441 panic(fmt.Sprintf("invalid argument, not cli.Flag type: %T", args[i])) 1442 } 1443 // Check if next arg extends current and expand its name if so 1444 name := flag.GetName() 1445 1446 if i+1 < len(args) { 1447 switch option := args[i+1].(type) { 1448 case string: 1449 // Extended flag check, make sure value set doesn't conflict with passed in option 1450 if ctx.GlobalString(flag.GetName()) == option { 1451 name += "=" + option 1452 set = append(set, "--"+name) 1453 } 1454 // shift arguments and continue 1455 i++ 1456 continue 1457 1458 case cli.Flag: 1459 default: 1460 panic(fmt.Sprintf("invalid argument, not cli.Flag or string extension: %T", args[i+1])) 1461 } 1462 } 1463 // Mark the flag if it's set 1464 if ctx.GlobalIsSet(flag.GetName()) { 1465 set = append(set, "--"+name) 1466 } 1467 } 1468 if len(set) > 1 { 1469 Fatalf("Flags %v can't be used at the same time", strings.Join(set, ", ")) 1470 } 1471 } 1472 1473 // SetEthConfig applies eth-related command line flags to the config. 1474 func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *ethconfig.Config) { 1475 // Avoid conflicting network flags 1476 CheckExclusive(ctx, MainnetFlag, DeveloperFlag, RopstenFlag, RinkebyFlag, GoerliFlag) 1477 CheckExclusive(ctx, LightServeFlag, SyncModeFlag, "light") 1478 CheckExclusive(ctx, DeveloperFlag, ExternalSignerFlag) // Can't use both ephemeral unlocked and external signer 1479 if ctx.GlobalString(GCModeFlag.Name) == "archive" && ctx.GlobalUint64(TxLookupLimitFlag.Name) != 0 { 1480 ctx.GlobalSet(TxLookupLimitFlag.Name, "0") 1481 log.Warn("Disable transaction unindexing for archive node") 1482 } 1483 if ctx.GlobalIsSet(LightServeFlag.Name) && ctx.GlobalUint64(TxLookupLimitFlag.Name) != 0 { 1484 log.Warn("LES server cannot serve old transaction status and cannot connect below les/4 protocol version if transaction lookup index is limited") 1485 } 1486 var ks *keystore.KeyStore 1487 if keystores := stack.AccountManager().Backends(keystore.KeyStoreType); len(keystores) > 0 { 1488 ks = keystores[0].(*keystore.KeyStore) 1489 } 1490 setEtherbase(ctx, ks, cfg) 1491 setGPO(ctx, &cfg.GPO, ctx.GlobalString(SyncModeFlag.Name) == "light") 1492 setTxPool(ctx, &cfg.TxPool) 1493 setEthash(ctx, cfg) 1494 setMiner(ctx, &cfg.Miner) 1495 setWhitelist(ctx, cfg) 1496 setLes(ctx, cfg) 1497 1498 // Cap the cache allowance and tune the garbage collector 1499 mem, err := gopsutil.VirtualMemory() 1500 if err == nil { 1501 if 32<<(^uintptr(0)>>63) == 32 && mem.Total > 2*1024*1024*1024 { 1502 log.Warn("Lowering memory allowance on 32bit arch", "available", mem.Total/1024/1024, "addressable", 2*1024) 1503 mem.Total = 2 * 1024 * 1024 * 1024 1504 } 1505 allowance := int(mem.Total / 1024 / 1024 / 3) 1506 if cache := ctx.GlobalInt(CacheFlag.Name); cache > allowance { 1507 log.Warn("Sanitizing cache to Go's GC limits", "provided", cache, "updated", allowance) 1508 ctx.GlobalSet(CacheFlag.Name, strconv.Itoa(allowance)) 1509 } 1510 } 1511 // Ensure Go's GC ignores the database cache for trigger percentage 1512 cache := ctx.GlobalInt(CacheFlag.Name) 1513 gogc := math.Max(20, math.Min(100, 100/(float64(cache)/1024))) 1514 1515 log.Debug("Sanitizing Go's GC trigger", "percent", int(gogc)) 1516 godebug.SetGCPercent(int(gogc)) 1517 1518 if ctx.GlobalIsSet(SyncModeFlag.Name) { 1519 cfg.SyncMode = *GlobalTextMarshaler(ctx, SyncModeFlag.Name).(*downloader.SyncMode) 1520 } 1521 if ctx.GlobalIsSet(NetworkIdFlag.Name) { 1522 cfg.NetworkId = ctx.GlobalUint64(NetworkIdFlag.Name) 1523 } 1524 if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheDatabaseFlag.Name) { 1525 cfg.DatabaseCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheDatabaseFlag.Name) / 100 1526 } 1527 cfg.DatabaseHandles = MakeDatabaseHandles() 1528 if ctx.GlobalIsSet(AncientFlag.Name) { 1529 cfg.DatabaseFreezer = ctx.GlobalString(AncientFlag.Name) 1530 } 1531 1532 if gcmode := ctx.GlobalString(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" { 1533 Fatalf("--%s must be either 'full' or 'archive'", GCModeFlag.Name) 1534 } 1535 if ctx.GlobalIsSet(GCModeFlag.Name) { 1536 cfg.NoPruning = ctx.GlobalString(GCModeFlag.Name) == "archive" 1537 } 1538 if ctx.GlobalIsSet(CacheNoPrefetchFlag.Name) { 1539 cfg.NoPrefetch = ctx.GlobalBool(CacheNoPrefetchFlag.Name) 1540 } 1541 // Read the value from the flag no matter if it's set or not. 1542 cfg.Preimages = ctx.GlobalBool(CachePreimagesFlag.Name) 1543 if cfg.NoPruning && !cfg.Preimages { 1544 cfg.Preimages = true 1545 log.Info("Enabling recording of key preimages since archive mode is used") 1546 } 1547 if ctx.GlobalIsSet(TxLookupLimitFlag.Name) { 1548 cfg.TxLookupLimit = ctx.GlobalUint64(TxLookupLimitFlag.Name) 1549 } 1550 if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheTrieFlag.Name) { 1551 cfg.TrieCleanCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheTrieFlag.Name) / 100 1552 } 1553 if ctx.GlobalIsSet(CacheTrieJournalFlag.Name) { 1554 cfg.TrieCleanCacheJournal = ctx.GlobalString(CacheTrieJournalFlag.Name) 1555 } 1556 if ctx.GlobalIsSet(CacheTrieRejournalFlag.Name) { 1557 cfg.TrieCleanCacheRejournal = ctx.GlobalDuration(CacheTrieRejournalFlag.Name) 1558 } 1559 if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheGCFlag.Name) { 1560 cfg.TrieDirtyCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheGCFlag.Name) / 100 1561 } 1562 if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheSnapshotFlag.Name) { 1563 cfg.SnapshotCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheSnapshotFlag.Name) / 100 1564 } 1565 if !ctx.GlobalBool(SnapshotFlag.Name) { 1566 // If snap-sync is requested, this flag is also required 1567 if cfg.SyncMode == downloader.SnapSync { 1568 log.Info("Snap sync requested, enabling --snapshot") 1569 } else { 1570 cfg.TrieCleanCache += cfg.SnapshotCache 1571 cfg.SnapshotCache = 0 // Disabled 1572 } 1573 } 1574 if ctx.GlobalIsSet(DocRootFlag.Name) { 1575 cfg.DocRoot = ctx.GlobalString(DocRootFlag.Name) 1576 } 1577 if ctx.GlobalIsSet(VMEnableDebugFlag.Name) { 1578 // TODO(fjl): force-enable this in --dev mode 1579 cfg.EnablePreimageRecording = ctx.GlobalBool(VMEnableDebugFlag.Name) 1580 } 1581 1582 if ctx.GlobalIsSet(RPCGlobalGasCapFlag.Name) { 1583 cfg.RPCGasCap = ctx.GlobalUint64(RPCGlobalGasCapFlag.Name) 1584 } 1585 if cfg.RPCGasCap != 0 { 1586 log.Info("Set global gas cap", "cap", cfg.RPCGasCap) 1587 } else { 1588 log.Info("Global gas cap disabled") 1589 } 1590 if ctx.GlobalIsSet(RPCGlobalTxFeeCapFlag.Name) { 1591 cfg.RPCTxFeeCap = ctx.GlobalFloat64(RPCGlobalTxFeeCapFlag.Name) 1592 } 1593 if ctx.GlobalIsSet(NoDiscoverFlag.Name) { 1594 cfg.EthDiscoveryURLs, cfg.SnapDiscoveryURLs = []string{}, []string{} 1595 } else if ctx.GlobalIsSet(DNSDiscoveryFlag.Name) { 1596 urls := ctx.GlobalString(DNSDiscoveryFlag.Name) 1597 if urls == "" { 1598 cfg.EthDiscoveryURLs = []string{} 1599 } else { 1600 cfg.EthDiscoveryURLs = SplitAndTrim(urls) 1601 } 1602 } 1603 // Override any default configs for hard coded networks. 1604 switch { 1605 case ctx.GlobalBool(MainnetFlag.Name): 1606 if !ctx.GlobalIsSet(NetworkIdFlag.Name) { 1607 cfg.NetworkId = 1 1608 } 1609 cfg.Genesis = core.DefaultGenesisBlock() 1610 SetDNSDiscoveryDefaults(cfg, params.MainnetGenesisHash) 1611 case ctx.GlobalBool(RopstenFlag.Name): 1612 if !ctx.GlobalIsSet(NetworkIdFlag.Name) { 1613 cfg.NetworkId = 3 1614 } 1615 cfg.Genesis = core.DefaultRopstenGenesisBlock() 1616 SetDNSDiscoveryDefaults(cfg, params.RopstenGenesisHash) 1617 case ctx.GlobalBool(RinkebyFlag.Name): 1618 if !ctx.GlobalIsSet(NetworkIdFlag.Name) { 1619 cfg.NetworkId = 4 1620 } 1621 cfg.Genesis = core.DefaultRinkebyGenesisBlock() 1622 SetDNSDiscoveryDefaults(cfg, params.RinkebyGenesisHash) 1623 case ctx.GlobalBool(GoerliFlag.Name): 1624 if !ctx.GlobalIsSet(NetworkIdFlag.Name) { 1625 cfg.NetworkId = 5 1626 } 1627 cfg.Genesis = core.DefaultGoerliGenesisBlock() 1628 SetDNSDiscoveryDefaults(cfg, params.GoerliGenesisHash) 1629 case ctx.GlobalBool(DeveloperFlag.Name): 1630 if !ctx.GlobalIsSet(NetworkIdFlag.Name) { 1631 cfg.NetworkId = 1337 1632 } 1633 cfg.SyncMode = downloader.FullSync 1634 // Create new developer account or reuse existing one 1635 var ( 1636 developer accounts.Account 1637 passphrase string 1638 err error 1639 ) 1640 if list := MakePasswordList(ctx); len(list) > 0 { 1641 // Just take the first value. Although the function returns a possible multiple values and 1642 // some usages iterate through them as attempts, that doesn't make sense in this setting, 1643 // when we're definitely concerned with only one account. 1644 passphrase = list[0] 1645 } 1646 // setEtherbase has been called above, configuring the miner address from command line flags. 1647 if cfg.Miner.Etherbase != (common.Address{}) { 1648 developer = accounts.Account{Address: cfg.Miner.Etherbase} 1649 } else if accs := ks.Accounts(); len(accs) > 0 { 1650 developer = ks.Accounts()[0] 1651 } else { 1652 developer, err = ks.NewAccount(passphrase) 1653 if err != nil { 1654 Fatalf("Failed to create developer account: %v", err) 1655 } 1656 } 1657 if err := ks.Unlock(developer, passphrase); err != nil { 1658 Fatalf("Failed to unlock developer account: %v", err) 1659 } 1660 log.Info("Using developer account", "address", developer.Address) 1661 1662 // Create a new developer genesis block or reuse existing one 1663 cfg.Genesis = core.DeveloperGenesisBlock(uint64(ctx.GlobalInt(DeveloperPeriodFlag.Name)), developer.Address) 1664 if ctx.GlobalIsSet(DataDirFlag.Name) { 1665 // Check if we have an already initialized chain and fall back to 1666 // that if so. Otherwise we need to generate a new genesis spec. 1667 chaindb := MakeChainDatabase(ctx, stack, false) // TODO (MariusVanDerWijden) make this read only 1668 if rawdb.ReadCanonicalHash(chaindb, 0) != (common.Hash{}) { 1669 cfg.Genesis = nil // fallback to db content 1670 } 1671 chaindb.Close() 1672 } 1673 if !ctx.GlobalIsSet(MinerGasPriceFlag.Name) { 1674 cfg.Miner.GasPrice = big.NewInt(1) 1675 } 1676 default: 1677 if cfg.NetworkId == 1 { 1678 SetDNSDiscoveryDefaults(cfg, params.MainnetGenesisHash) 1679 } 1680 } 1681 } 1682 1683 // SetDNSDiscoveryDefaults configures DNS discovery with the given URL if 1684 // no URLs are set. 1685 func SetDNSDiscoveryDefaults(cfg *ethconfig.Config, genesis common.Hash) { 1686 if cfg.EthDiscoveryURLs != nil { 1687 return // already set through flags/config 1688 } 1689 protocol := "all" 1690 if cfg.SyncMode == downloader.LightSync { 1691 protocol = "les" 1692 } 1693 if url := params.KnownDNSNetwork(genesis, protocol); url != "" { 1694 cfg.EthDiscoveryURLs = []string{url} 1695 cfg.SnapDiscoveryURLs = cfg.EthDiscoveryURLs 1696 } 1697 } 1698 1699 // RegisterEthService adds an Ethereum client to the stack. 1700 // The second return value is the full node instance, which may be nil if the 1701 // node is running as a light client. 1702 func RegisterEthService(stack *node.Node, cfg *ethconfig.Config) (ethapi.Backend, *eth.Ethereum) { 1703 if cfg.SyncMode == downloader.LightSync { 1704 backend, err := les.New(stack, cfg) 1705 if err != nil { 1706 Fatalf("Failed to register the Ethereum service: %v", err) 1707 } 1708 stack.RegisterAPIs(tracers.APIs(backend.ApiBackend)) 1709 return backend.ApiBackend, nil 1710 } 1711 backend, err := eth.New(stack, cfg) 1712 if err != nil { 1713 Fatalf("Failed to register the Ethereum service: %v", err) 1714 } 1715 if cfg.LightServ > 0 { 1716 _, err := les.NewLesServer(stack, backend, cfg) 1717 if err != nil { 1718 Fatalf("Failed to create the LES server: %v", err) 1719 } 1720 } 1721 stack.RegisterAPIs(tracers.APIs(backend.APIBackend)) 1722 return backend.APIBackend, backend 1723 } 1724 1725 // RegisterEthStatsService configures the Ethereum Stats daemon and adds it to 1726 // the given node. 1727 func RegisterEthStatsService(stack *node.Node, backend ethapi.Backend, url string) { 1728 if err := ethstats.New(stack, backend, backend.Engine(), url); err != nil { 1729 Fatalf("Failed to register the Ethereum Stats service: %v", err) 1730 } 1731 } 1732 1733 // RegisterGraphQLService is a utility function to construct a new service and register it against a node. 1734 func RegisterGraphQLService(stack *node.Node, backend ethapi.Backend, cfg node.Config) { 1735 if err := graphql.New(stack, backend, cfg.GraphQLCors, cfg.GraphQLVirtualHosts); err != nil { 1736 Fatalf("Failed to register the GraphQL service: %v", err) 1737 } 1738 } 1739 1740 func SetupMetrics(ctx *cli.Context) { 1741 if metrics.Enabled { 1742 log.Info("Enabling metrics collection") 1743 1744 var ( 1745 enableExport = ctx.GlobalBool(MetricsEnableInfluxDBFlag.Name) 1746 enableExportV2 = ctx.GlobalBool(MetricsEnableInfluxDBV2Flag.Name) 1747 ) 1748 1749 if enableExport || enableExportV2 { 1750 CheckExclusive(ctx, MetricsEnableInfluxDBFlag, MetricsEnableInfluxDBV2Flag) 1751 1752 v1FlagIsSet := ctx.GlobalIsSet(MetricsInfluxDBUsernameFlag.Name) || 1753 ctx.GlobalIsSet(MetricsInfluxDBPasswordFlag.Name) 1754 1755 v2FlagIsSet := ctx.GlobalIsSet(MetricsInfluxDBTokenFlag.Name) || 1756 ctx.GlobalIsSet(MetricsInfluxDBOrganizationFlag.Name) || 1757 ctx.GlobalIsSet(MetricsInfluxDBBucketFlag.Name) 1758 1759 if enableExport && v2FlagIsSet { 1760 Fatalf("Flags --influxdb.metrics.organization, --influxdb.metrics.token, --influxdb.metrics.bucket are only available for influxdb-v2") 1761 } else if enableExportV2 && v1FlagIsSet { 1762 Fatalf("Flags --influxdb.metrics.username, --influxdb.metrics.password are only available for influxdb-v1") 1763 } 1764 } 1765 1766 var ( 1767 endpoint = ctx.GlobalString(MetricsInfluxDBEndpointFlag.Name) 1768 database = ctx.GlobalString(MetricsInfluxDBDatabaseFlag.Name) 1769 username = ctx.GlobalString(MetricsInfluxDBUsernameFlag.Name) 1770 password = ctx.GlobalString(MetricsInfluxDBPasswordFlag.Name) 1771 1772 token = ctx.GlobalString(MetricsInfluxDBTokenFlag.Name) 1773 bucket = ctx.GlobalString(MetricsInfluxDBBucketFlag.Name) 1774 organization = ctx.GlobalString(MetricsInfluxDBOrganizationFlag.Name) 1775 ) 1776 1777 if enableExport { 1778 tagsMap := SplitTagsFlag(ctx.GlobalString(MetricsInfluxDBTagsFlag.Name)) 1779 1780 log.Info("Enabling metrics export to InfluxDB") 1781 1782 go influxdb.InfluxDBWithTags(metrics.DefaultRegistry, 10*time.Second, endpoint, database, username, password, "geth.", tagsMap) 1783 } else if enableExportV2 { 1784 tagsMap := SplitTagsFlag(ctx.GlobalString(MetricsInfluxDBTagsFlag.Name)) 1785 1786 log.Info("Enabling metrics export to InfluxDB (v2)") 1787 1788 go influxdb.InfluxDBV2WithTags(metrics.DefaultRegistry, 10*time.Second, endpoint, token, bucket, organization, "geth.", tagsMap) 1789 } 1790 1791 if ctx.GlobalIsSet(MetricsHTTPFlag.Name) { 1792 address := fmt.Sprintf("%s:%d", ctx.GlobalString(MetricsHTTPFlag.Name), ctx.GlobalInt(MetricsPortFlag.Name)) 1793 log.Info("Enabling stand-alone metrics HTTP endpoint", "address", address) 1794 exp.Setup(address) 1795 } 1796 } 1797 } 1798 1799 func SplitTagsFlag(tagsFlag string) map[string]string { 1800 tags := strings.Split(tagsFlag, ",") 1801 tagsMap := map[string]string{} 1802 1803 for _, t := range tags { 1804 if t != "" { 1805 kv := strings.Split(t, "=") 1806 1807 if len(kv) == 2 { 1808 tagsMap[kv[0]] = kv[1] 1809 } 1810 } 1811 } 1812 1813 return tagsMap 1814 } 1815 1816 // MakeChainDatabase open an LevelDB using the flags passed to the client and will hard crash if it fails. 1817 func MakeChainDatabase(ctx *cli.Context, stack *node.Node, readonly bool) ethdb.Database { 1818 var ( 1819 cache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheDatabaseFlag.Name) / 100 1820 handles = MakeDatabaseHandles() 1821 1822 err error 1823 chainDb ethdb.Database 1824 ) 1825 if ctx.GlobalString(SyncModeFlag.Name) == "light" { 1826 name := "lightchaindata" 1827 chainDb, err = stack.OpenDatabase(name, cache, handles, "", readonly) 1828 } else { 1829 name := "chaindata" 1830 chainDb, err = stack.OpenDatabaseWithFreezer(name, cache, handles, ctx.GlobalString(AncientFlag.Name), "", readonly) 1831 } 1832 if err != nil { 1833 Fatalf("Could not open database: %v", err) 1834 } 1835 return chainDb 1836 } 1837 1838 func MakeGenesis(ctx *cli.Context) *core.Genesis { 1839 var genesis *core.Genesis 1840 switch { 1841 case ctx.GlobalBool(MainnetFlag.Name): 1842 genesis = core.DefaultGenesisBlock() 1843 case ctx.GlobalBool(RopstenFlag.Name): 1844 genesis = core.DefaultRopstenGenesisBlock() 1845 case ctx.GlobalBool(RinkebyFlag.Name): 1846 genesis = core.DefaultRinkebyGenesisBlock() 1847 case ctx.GlobalBool(GoerliFlag.Name): 1848 genesis = core.DefaultGoerliGenesisBlock() 1849 case ctx.GlobalBool(DeveloperFlag.Name): 1850 Fatalf("Developer chains are ephemeral") 1851 } 1852 return genesis 1853 } 1854 1855 // MakeChain creates a chain manager from set command line flags. 1856 func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chainDb ethdb.Database) { 1857 var err error 1858 chainDb = MakeChainDatabase(ctx, stack, false) // TODO(rjl493456442) support read-only database 1859 config, _, err := core.SetupGenesisBlock(chainDb, MakeGenesis(ctx)) 1860 if err != nil { 1861 Fatalf("%v", err) 1862 } 1863 var engine consensus.Engine 1864 if config.Clique != nil { 1865 engine = clique.New(config.Clique, chainDb) 1866 } else { 1867 engine = ethash.NewFaker() 1868 if !ctx.GlobalBool(FakePoWFlag.Name) { 1869 engine = ethash.New(ethash.Config{ 1870 CacheDir: stack.ResolvePath(ethconfig.Defaults.Ethash.CacheDir), 1871 CachesInMem: ethconfig.Defaults.Ethash.CachesInMem, 1872 CachesOnDisk: ethconfig.Defaults.Ethash.CachesOnDisk, 1873 CachesLockMmap: ethconfig.Defaults.Ethash.CachesLockMmap, 1874 DatasetDir: stack.ResolvePath(ethconfig.Defaults.Ethash.DatasetDir), 1875 DatasetsInMem: ethconfig.Defaults.Ethash.DatasetsInMem, 1876 DatasetsOnDisk: ethconfig.Defaults.Ethash.DatasetsOnDisk, 1877 DatasetsLockMmap: ethconfig.Defaults.Ethash.DatasetsLockMmap, 1878 }, nil, false) 1879 } 1880 } 1881 if gcmode := ctx.GlobalString(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" { 1882 Fatalf("--%s must be either 'full' or 'archive'", GCModeFlag.Name) 1883 } 1884 cache := &core.CacheConfig{ 1885 TrieCleanLimit: ethconfig.Defaults.TrieCleanCache, 1886 TrieCleanNoPrefetch: ctx.GlobalBool(CacheNoPrefetchFlag.Name), 1887 TrieDirtyLimit: ethconfig.Defaults.TrieDirtyCache, 1888 TrieDirtyDisabled: ctx.GlobalString(GCModeFlag.Name) == "archive", 1889 TrieTimeLimit: ethconfig.Defaults.TrieTimeout, 1890 SnapshotLimit: ethconfig.Defaults.SnapshotCache, 1891 Preimages: ctx.GlobalBool(CachePreimagesFlag.Name), 1892 } 1893 if cache.TrieDirtyDisabled && !cache.Preimages { 1894 cache.Preimages = true 1895 log.Info("Enabling recording of key preimages since archive mode is used") 1896 } 1897 if !ctx.GlobalBool(SnapshotFlag.Name) { 1898 cache.SnapshotLimit = 0 // Disabled 1899 } 1900 if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheTrieFlag.Name) { 1901 cache.TrieCleanLimit = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheTrieFlag.Name) / 100 1902 } 1903 if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheGCFlag.Name) { 1904 cache.TrieDirtyLimit = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheGCFlag.Name) / 100 1905 } 1906 vmcfg := vm.Config{EnablePreimageRecording: ctx.GlobalBool(VMEnableDebugFlag.Name)} 1907 1908 // TODO(rjl493456442) disable snapshot generation/wiping if the chain is read only. 1909 // Disable transaction indexing/unindexing by default. 1910 chain, err = core.NewBlockChain(chainDb, cache, config, engine, vmcfg, nil, nil) 1911 if err != nil { 1912 Fatalf("Can't create BlockChain: %v", err) 1913 } 1914 return chain, chainDb 1915 } 1916 1917 // MakeConsolePreloads retrieves the absolute paths for the console JavaScript 1918 // scripts to preload before starting. 1919 func MakeConsolePreloads(ctx *cli.Context) []string { 1920 // Skip preloading if there's nothing to preload 1921 if ctx.GlobalString(PreloadJSFlag.Name) == "" { 1922 return nil 1923 } 1924 // Otherwise resolve absolute paths and return them 1925 var preloads []string 1926 1927 for _, file := range strings.Split(ctx.GlobalString(PreloadJSFlag.Name), ",") { 1928 preloads = append(preloads, strings.TrimSpace(file)) 1929 } 1930 return preloads 1931 } 1932 1933 // MigrateFlags sets the global flag from a local flag when it's set. 1934 // This is a temporary function used for migrating old command/flags to the 1935 // new format. 1936 // 1937 // e.g. geth account new --keystore /tmp/mykeystore --lightkdf 1938 // 1939 // is equivalent after calling this method with: 1940 // 1941 // geth --keystore /tmp/mykeystore --lightkdf account new 1942 // 1943 // This allows the use of the existing configuration functionality. 1944 // When all flags are migrated this function can be removed and the existing 1945 // configuration functionality must be changed that is uses local flags 1946 func MigrateFlags(action func(ctx *cli.Context) error) func(*cli.Context) error { 1947 return func(ctx *cli.Context) error { 1948 for _, name := range ctx.FlagNames() { 1949 if ctx.IsSet(name) { 1950 ctx.GlobalSet(name, ctx.String(name)) 1951 } 1952 } 1953 return action(ctx) 1954 } 1955 }