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