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