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