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