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