|
| 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 main |
| 18 | + |
| 19 | +import ( |
| 20 | + "bufio" |
| 21 | + "encoding/hex" |
| 22 | + "errors" |
| 23 | + "fmt" |
| 24 | + "io" |
| 25 | + "os" |
| 26 | + "reflect" |
| 27 | + "unicode" |
| 28 | + |
| 29 | + cli "gopkg.in/urfave/cli.v1" |
| 30 | + |
| 31 | + "github.com/ethereum/go-ethereum/cmd/utils" |
| 32 | + "github.com/ethereum/go-ethereum/contracts/release" |
| 33 | + "github.com/ethereum/go-ethereum/eth" |
| 34 | + "github.com/ethereum/go-ethereum/node" |
| 35 | + "github.com/ethereum/go-ethereum/params" |
| 36 | + "github.com/naoina/toml" |
| 37 | +) |
| 38 | + |
| 39 | +var ( |
| 40 | + dumpConfigCommand = cli.Command{ |
| 41 | + Action: dumpConfig, |
| 42 | + Name: "dumpconfig", |
| 43 | + Usage: "Show configuration values", |
| 44 | + ArgsUsage: "", |
| 45 | + Category: "MISCELLANEOUS COMMANDS", |
| 46 | + Description: `The dumpconfig command shows configuration values.`, |
| 47 | + } |
| 48 | + |
| 49 | + configFileFlag = cli.StringFlag{ |
| 50 | + Name: "config", |
| 51 | + Usage: "TOML configuration file", |
| 52 | + } |
| 53 | +) |
| 54 | + |
| 55 | +// These settings ensure that TOML keys use the same names as Go struct fields. |
| 56 | +var tomlSettings = toml.Config{ |
| 57 | + NormFieldName: func(rt reflect.Type, key string) string { |
| 58 | + return key |
| 59 | + }, |
| 60 | + FieldToKey: func(rt reflect.Type, field string) string { |
| 61 | + return field |
| 62 | + }, |
| 63 | + MissingField: func(rt reflect.Type, field string) error { |
| 64 | + link := "" |
| 65 | + if unicode.IsUpper(rune(rt.Name()[0])) && rt.PkgPath() != "main" { |
| 66 | + link = fmt.Sprintf(", see https://godoc.org/%s#%s for available fields", rt.PkgPath(), rt.Name()) |
| 67 | + } |
| 68 | + return fmt.Errorf("field '%s' is not defined in %s%s", field, rt.String(), link) |
| 69 | + }, |
| 70 | +} |
| 71 | + |
| 72 | +type ethstatsConfig struct { |
| 73 | + URL string `toml:",omitempty"` |
| 74 | +} |
| 75 | + |
| 76 | +type gethConfig struct { |
| 77 | + Eth eth.Config |
| 78 | + Node node.Config |
| 79 | + Ethstats ethstatsConfig |
| 80 | +} |
| 81 | + |
| 82 | +func loadConfig(file string, cfg *gethConfig) error { |
| 83 | + f, err := os.Open(file) |
| 84 | + if err != nil { |
| 85 | + return err |
| 86 | + } |
| 87 | + defer f.Close() |
| 88 | + |
| 89 | + err = tomlSettings.NewDecoder(bufio.NewReader(f)).Decode(cfg) |
| 90 | + // Add file name to errors that have a line number. |
| 91 | + if _, ok := err.(*toml.LineError); ok { |
| 92 | + err = errors.New(file + ", " + err.Error()) |
| 93 | + } |
| 94 | + return err |
| 95 | +} |
| 96 | + |
| 97 | +func defaultNodeConfig() node.Config { |
| 98 | + cfg := node.DefaultConfig |
| 99 | + cfg.Name = clientIdentifier |
| 100 | + cfg.Version = params.VersionWithCommit(gitCommit) |
| 101 | + cfg.HTTPModules = append(cfg.HTTPModules, "eth") |
| 102 | + cfg.WSModules = append(cfg.WSModules, "eth") |
| 103 | + cfg.IPCPath = "geth.ipc" |
| 104 | + return cfg |
| 105 | +} |
| 106 | + |
| 107 | +func makeConfigNode(ctx *cli.Context) (*node.Node, gethConfig) { |
| 108 | + // Load defaults. |
| 109 | + cfg := gethConfig{ |
| 110 | + Eth: eth.DefaultConfig, |
| 111 | + Node: defaultNodeConfig(), |
| 112 | + } |
| 113 | + |
| 114 | + // Load config file. |
| 115 | + if file := ctx.GlobalString(configFileFlag.Name); file != "" { |
| 116 | + if err := loadConfig(file, &cfg); err != nil { |
| 117 | + utils.Fatalf("%v", err) |
| 118 | + } |
| 119 | + } |
| 120 | + |
| 121 | + // Apply flags. |
| 122 | + utils.SetNodeConfig(ctx, &cfg.Node) |
| 123 | + stack, err := node.New(&cfg.Node) |
| 124 | + if err != nil { |
| 125 | + utils.Fatalf("Failed to create the protocol stack: %v", err) |
| 126 | + } |
| 127 | + utils.SetEthConfig(ctx, stack, &cfg.Eth) |
| 128 | + if ctx.GlobalIsSet(utils.EthStatsURLFlag.Name) { |
| 129 | + cfg.Ethstats.URL = ctx.GlobalString(utils.EthStatsURLFlag.Name) |
| 130 | + } |
| 131 | + |
| 132 | + return stack, cfg |
| 133 | +} |
| 134 | + |
| 135 | +func makeFullNode(ctx *cli.Context) *node.Node { |
| 136 | + stack, cfg := makeConfigNode(ctx) |
| 137 | + |
| 138 | + utils.RegisterEthService(stack, &cfg.Eth) |
| 139 | + |
| 140 | + // Whisper must be explicitly enabled, but is auto-enabled in --dev mode. |
| 141 | + shhEnabled := ctx.GlobalBool(utils.WhisperEnabledFlag.Name) |
| 142 | + shhAutoEnabled := !ctx.GlobalIsSet(utils.WhisperEnabledFlag.Name) && ctx.GlobalIsSet(utils.DevModeFlag.Name) |
| 143 | + if shhEnabled || shhAutoEnabled { |
| 144 | + utils.RegisterShhService(stack) |
| 145 | + } |
| 146 | + |
| 147 | + // Add the Ethereum Stats daemon if requested. |
| 148 | + if cfg.Ethstats.URL != "" { |
| 149 | + utils.RegisterEthStatsService(stack, cfg.Ethstats.URL) |
| 150 | + } |
| 151 | + |
| 152 | + // Add the release oracle service so it boots along with node. |
| 153 | + if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { |
| 154 | + config := release.Config{ |
| 155 | + Oracle: relOracle, |
| 156 | + Major: uint32(params.VersionMajor), |
| 157 | + Minor: uint32(params.VersionMinor), |
| 158 | + Patch: uint32(params.VersionPatch), |
| 159 | + } |
| 160 | + commit, _ := hex.DecodeString(gitCommit) |
| 161 | + copy(config.Commit[:], commit) |
| 162 | + return release.NewReleaseService(ctx, config) |
| 163 | + }); err != nil { |
| 164 | + utils.Fatalf("Failed to register the Geth release oracle service: %v", err) |
| 165 | + } |
| 166 | + return stack |
| 167 | +} |
| 168 | + |
| 169 | +// dumpConfig is the dumpconfig command. |
| 170 | +func dumpConfig(ctx *cli.Context) error { |
| 171 | + _, cfg := makeConfigNode(ctx) |
| 172 | + comment := "" |
| 173 | + |
| 174 | + if cfg.Eth.Genesis != nil { |
| 175 | + cfg.Eth.Genesis = nil |
| 176 | + comment += "# Note: this config doesn't contain the genesis block.\n\n" |
| 177 | + } |
| 178 | + |
| 179 | + out, err := tomlSettings.Marshal(&cfg) |
| 180 | + if err != nil { |
| 181 | + return err |
| 182 | + } |
| 183 | + io.WriteString(os.Stdout, comment) |
| 184 | + os.Stdout.Write(out) |
| 185 | + return nil |
| 186 | +} |
0 commit comments