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