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