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