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