// Copyright 2017 The go-ethereum Authors // This file is part of go-ethereum. // // go-ethereum is free software: you can redistribute it and/or modify // it under the terms of the GNU General Public License as published by // the Free Software Foundation, either version 3 of the License, or // (at your option) any later version. // // go-ethereum is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the // GNU General Public License for more details. // // You should have received a copy of the GNU General Public License // along with go-ethereum. If not, see . package main import ( "fmt" "io/ioutil" "math/big" "os" "time" "gopkg.in/urfave/cli.v1" "github.com/BurntSushi/toml" "github.com/ethereum/go-ethereum/accounts/external" "github.com/ethereum/go-ethereum/accounts/keystore" "github.com/ethereum/go-ethereum/accounts/scwallet" "github.com/ethereum/go-ethereum/accounts/usbwallet" "github.com/ethereum/go-ethereum/cmd/utils" "github.com/ethereum/go-ethereum/core/rawdb" "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/eth/ethconfig" "github.com/ethereum/go-ethereum/internal/ethapi" "github.com/ethereum/go-ethereum/log" "github.com/ethereum/go-ethereum/metrics" "github.com/ethereum/go-ethereum/node" "github.com/ethereum/go-ethereum/params" ) var ( dumpConfigCommand = cli.Command{ Action: utils.MigrateFlags(dumpConfig), Name: "dumpconfig", Usage: "Show configuration values", ArgsUsage: "", Flags: append(nodeFlags, rpcFlags...), Category: "MISCELLANEOUS COMMANDS", Description: `The dumpconfig command shows configuration values.`, } configFileFlag = cli.StringFlag{ Name: "config", Usage: "TOML configuration file", } ) type ethstatsConfig struct { URL string `toml:",omitempty"` } type gethConfig struct { Eth ethconfig.Config Node node.Config Ethstats ethstatsConfig Metrics metrics.Config } func loadConfig(file string, cfg *gethConfig) error { data, err := ioutil.ReadFile(file) if err != nil { return err } tomlData := string(data) if _, err = toml.Decode(tomlData, &cfg); err != nil { return err } return nil } func defaultNodeConfig() node.Config { cfg := node.DefaultConfig cfg.Name = clientIdentifier cfg.Version = params.VersionWithCommit(gitCommit, gitDate) cfg.HTTPModules = append(cfg.HTTPModules, "eth") cfg.WSModules = append(cfg.WSModules, "eth") cfg.IPCPath = clientIdentifier + ".ipc" return cfg } // makeConfigNode loads geth configuration and creates a blank node instance. func makeConfigNode(ctx *cli.Context) (*node.Node, gethConfig) { // Load defaults. cfg := gethConfig{ Eth: ethconfig.Defaults, Node: defaultNodeConfig(), Metrics: metrics.DefaultConfig, } // Load config file. if file := ctx.GlobalString(configFileFlag.Name); file != "" { if err := loadConfig(file, &cfg); err != nil { utils.Fatalf("%v", err) } } if ctx.GlobalIsSet(utils.MumbaiFlag.Name) { setDefaultMumbaiGethConfig(ctx, &cfg) } if ctx.GlobalIsSet(utils.BorMainnetFlag.Name) { setDefaultBorMainnetGethConfig(ctx, &cfg) } // Apply flags. utils.SetNodeConfig(ctx, &cfg.Node) stack, err := node.New(&cfg.Node) if err != nil { utils.Fatalf("Failed to create the protocol stack: %v", err) } // Node doesn't by default populate account manager backends if err := setAccountManagerBackends(stack); err != nil { utils.Fatalf("Failed to set account manager backends: %v", err) } utils.SetEthConfig(ctx, stack, &cfg.Eth) if ctx.GlobalIsSet(utils.EthStatsURLFlag.Name) { cfg.Ethstats.URL = ctx.GlobalString(utils.EthStatsURLFlag.Name) } applyMetricConfig(ctx, &cfg) // Set Bor config flags utils.SetBorConfig(ctx, &cfg.Eth) return stack, cfg } // makeFullNode loads geth configuration and creates the Ethereum backend. func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) { stack, cfg := makeConfigNode(ctx) if ctx.GlobalIsSet(utils.OverrideArrowGlacierFlag.Name) { cfg.Eth.OverrideArrowGlacier = new(big.Int).SetUint64(ctx.GlobalUint64(utils.OverrideArrowGlacierFlag.Name)) } if ctx.GlobalIsSet(utils.OverrideTerminalTotalDifficulty.Name) { cfg.Eth.OverrideTerminalTotalDifficulty = new(big.Int).SetUint64(ctx.GlobalUint64(utils.OverrideTerminalTotalDifficulty.Name)) } backend, eth := utils.RegisterEthService(stack, &cfg.Eth) // Warn users to migrate if they have a legacy freezer format. if eth != nil { firstIdx := uint64(0) // Hack to speed up check for mainnet because we know // the first non-empty block. ghash := rawdb.ReadCanonicalHash(eth.ChainDb(), 0) if cfg.Eth.NetworkId == 1 && ghash == params.MainnetGenesisHash { firstIdx = 46147 } isLegacy, _, err := dbHasLegacyReceipts(eth.ChainDb(), firstIdx) if err != nil { log.Error("Failed to check db for legacy receipts", "err", err) } else if isLegacy { log.Warn("Database has receipts with a legacy format. Please run `geth db freezer-migrate`.") } } // Configure GraphQL if requested if ctx.GlobalIsSet(utils.GraphQLEnabledFlag.Name) { utils.RegisterGraphQLService(stack, backend, cfg.Node) } // Add the Ethereum Stats daemon if requested. if cfg.Ethstats.URL != "" { utils.RegisterEthStatsService(stack, backend, cfg.Ethstats.URL) } return stack, backend } // dumpConfig is the dumpconfig command. func dumpConfig(ctx *cli.Context) error { _, cfg := makeConfigNode(ctx) comment := "" if cfg.Eth.Genesis != nil { cfg.Eth.Genesis = nil comment += "# Note: this config doesn't contain the genesis block.\n\n" } if err := toml.NewEncoder(os.Stdout).Encode(&cfg); err != nil { return err } return nil } func applyMetricConfig(ctx *cli.Context, cfg *gethConfig) { if ctx.GlobalIsSet(utils.MetricsEnabledFlag.Name) { cfg.Metrics.Enabled = ctx.GlobalBool(utils.MetricsEnabledFlag.Name) } if ctx.GlobalIsSet(utils.MetricsEnabledExpensiveFlag.Name) { cfg.Metrics.EnabledExpensive = ctx.GlobalBool(utils.MetricsEnabledExpensiveFlag.Name) } if ctx.GlobalIsSet(utils.MetricsHTTPFlag.Name) { cfg.Metrics.HTTP = ctx.GlobalString(utils.MetricsHTTPFlag.Name) } if ctx.GlobalIsSet(utils.MetricsPortFlag.Name) { cfg.Metrics.Port = ctx.GlobalInt(utils.MetricsPortFlag.Name) } if ctx.GlobalIsSet(utils.MetricsEnableInfluxDBFlag.Name) { cfg.Metrics.EnableInfluxDB = ctx.GlobalBool(utils.MetricsEnableInfluxDBFlag.Name) } if ctx.GlobalIsSet(utils.MetricsInfluxDBEndpointFlag.Name) { cfg.Metrics.InfluxDBEndpoint = ctx.GlobalString(utils.MetricsInfluxDBEndpointFlag.Name) } if ctx.GlobalIsSet(utils.MetricsInfluxDBDatabaseFlag.Name) { cfg.Metrics.InfluxDBDatabase = ctx.GlobalString(utils.MetricsInfluxDBDatabaseFlag.Name) } if ctx.GlobalIsSet(utils.MetricsInfluxDBUsernameFlag.Name) { cfg.Metrics.InfluxDBUsername = ctx.GlobalString(utils.MetricsInfluxDBUsernameFlag.Name) } if ctx.GlobalIsSet(utils.MetricsInfluxDBPasswordFlag.Name) { cfg.Metrics.InfluxDBPassword = ctx.GlobalString(utils.MetricsInfluxDBPasswordFlag.Name) } if ctx.GlobalIsSet(utils.MetricsInfluxDBTagsFlag.Name) { cfg.Metrics.InfluxDBTags = ctx.GlobalString(utils.MetricsInfluxDBTagsFlag.Name) } if ctx.GlobalIsSet(utils.MetricsEnableInfluxDBV2Flag.Name) { cfg.Metrics.EnableInfluxDBV2 = ctx.GlobalBool(utils.MetricsEnableInfluxDBV2Flag.Name) } if ctx.GlobalIsSet(utils.MetricsInfluxDBTokenFlag.Name) { cfg.Metrics.InfluxDBToken = ctx.GlobalString(utils.MetricsInfluxDBTokenFlag.Name) } if ctx.GlobalIsSet(utils.MetricsInfluxDBBucketFlag.Name) { cfg.Metrics.InfluxDBBucket = ctx.GlobalString(utils.MetricsInfluxDBBucketFlag.Name) } if ctx.GlobalIsSet(utils.MetricsInfluxDBOrganizationFlag.Name) { cfg.Metrics.InfluxDBOrganization = ctx.GlobalString(utils.MetricsInfluxDBOrganizationFlag.Name) } } func deprecated(field string) bool { switch field { case "ethconfig.Config.EVMInterpreter": return true case "ethconfig.Config.EWASMInterpreter": return true default: return false } } func setAccountManagerBackends(stack *node.Node) error { conf := stack.Config() am := stack.AccountManager() keydir := stack.KeyStoreDir() scryptN := keystore.StandardScryptN scryptP := keystore.StandardScryptP if conf.UseLightweightKDF { scryptN = keystore.LightScryptN scryptP = keystore.LightScryptP } // Assemble the supported backends if len(conf.ExternalSigner) > 0 { log.Info("Using external signer", "url", conf.ExternalSigner) if extapi, err := external.NewExternalBackend(conf.ExternalSigner); err == nil { am.AddBackend(extapi) return nil } else { return fmt.Errorf("error connecting to external signer: %v", err) } } // For now, we're using EITHER external signer OR local signers. // If/when we implement some form of lockfile for USB and keystore wallets, // we can have both, but it's very confusing for the user to see the same // accounts in both externally and locally, plus very racey. am.AddBackend(keystore.NewKeyStore(keydir, scryptN, scryptP)) if conf.USB { // Start a USB hub for Ledger hardware wallets if ledgerhub, err := usbwallet.NewLedgerHub(); err != nil { log.Warn(fmt.Sprintf("Failed to start Ledger hub, disabling: %v", err)) } else { am.AddBackend(ledgerhub) } // Start a USB hub for Trezor hardware wallets (HID version) if trezorhub, err := usbwallet.NewTrezorHubWithHID(); err != nil { log.Warn(fmt.Sprintf("Failed to start HID Trezor hub, disabling: %v", err)) } else { am.AddBackend(trezorhub) } // Start a USB hub for Trezor hardware wallets (WebUSB version) if trezorhub, err := usbwallet.NewTrezorHubWithWebUSB(); err != nil { log.Warn(fmt.Sprintf("Failed to start WebUSB Trezor hub, disabling: %v", err)) } else { am.AddBackend(trezorhub) } } if len(conf.SmartCardDaemonPath) > 0 { // Start a smart card hub if schub, err := scwallet.NewHub(conf.SmartCardDaemonPath, scwallet.Scheme, keydir); err != nil { log.Warn(fmt.Sprintf("Failed to start smart card hub, disabling: %v", err)) } else { am.AddBackend(schub) } } return nil } func setDefaultMumbaiGethConfig(ctx *cli.Context, config *gethConfig) { config.Node.P2P.ListenAddr = fmt.Sprintf(":%d", 30303) config.Node.HTTPHost = "0.0.0.0" config.Node.HTTPVirtualHosts = []string{"*"} config.Node.HTTPCors = []string{"*"} config.Node.HTTPPort = 8545 config.Node.IPCPath = utils.MakeDataDir(ctx) + "/bor.ipc" config.Node.HTTPModules = []string{"eth", "net", "web3", "txpool", "bor"} config.Eth.SyncMode = downloader.FullSync config.Eth.NetworkId = 80001 config.Eth.Miner.GasCeil = 20000000 //--miner.gastarget is depreceated, No longed used config.Eth.TxPool.NoLocals = true config.Eth.TxPool.AccountSlots = 16 config.Eth.TxPool.GlobalSlots = 131072 config.Eth.TxPool.AccountQueue = 64 config.Eth.TxPool.GlobalQueue = 131072 config.Eth.TxPool.Lifetime = 90 * time.Minute config.Node.P2P.MaxPeers = 50 config.Metrics.Enabled = true // --pprof is enabled in 'internal/debug/flags.go' } func setDefaultBorMainnetGethConfig(ctx *cli.Context, config *gethConfig) { config.Node.P2P.ListenAddr = fmt.Sprintf(":%d", 30303) config.Node.HTTPHost = "0.0.0.0" config.Node.HTTPVirtualHosts = []string{"*"} config.Node.HTTPCors = []string{"*"} config.Node.HTTPPort = 8545 config.Node.IPCPath = utils.MakeDataDir(ctx) + "/bor.ipc" config.Node.HTTPModules = []string{"eth", "net", "web3", "txpool", "bor"} config.Eth.SyncMode = downloader.FullSync config.Eth.NetworkId = 137 config.Eth.Miner.GasCeil = 20000000 //--miner.gastarget is depreceated, No longed used config.Eth.TxPool.NoLocals = true config.Eth.TxPool.AccountSlots = 16 config.Eth.TxPool.GlobalSlots = 131072 config.Eth.TxPool.AccountQueue = 64 config.Eth.TxPool.GlobalQueue = 131072 config.Eth.TxPool.Lifetime = 90 * time.Minute config.Node.P2P.MaxPeers = 50 config.Metrics.Enabled = true // --pprof is enabled in 'internal/debug/flags.go' }