github.com/hyperion-hyn/go-ethereum@v2.4.0+incompatible/cmd/geth/config.go (about) 1 // Copyright 2017 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 "errors" 22 "fmt" 23 "io" 24 "os" 25 "reflect" 26 "time" 27 "unicode" 28 29 "gopkg.in/urfave/cli.v1" 30 31 "github.com/ethereum/go-ethereum/cmd/utils" 32 "github.com/ethereum/go-ethereum/dashboard" 33 "github.com/ethereum/go-ethereum/eth" 34 "github.com/ethereum/go-ethereum/node" 35 "github.com/ethereum/go-ethereum/p2p/enode" 36 "github.com/ethereum/go-ethereum/params" 37 "github.com/ethereum/go-ethereum/raft" 38 whisper "github.com/ethereum/go-ethereum/whisper/whisperv6" 39 "github.com/naoina/toml" 40 ) 41 42 var ( 43 dumpConfigCommand = cli.Command{ 44 Action: utils.MigrateFlags(dumpConfig), 45 Name: "dumpconfig", 46 Usage: "Show configuration values", 47 ArgsUsage: "", 48 Flags: append(append(nodeFlags, rpcFlags...), whisperFlags...), 49 Category: "MISCELLANEOUS COMMANDS", 50 Description: `The dumpconfig command shows configuration values.`, 51 } 52 53 configFileFlag = cli.StringFlag{ 54 Name: "config", 55 Usage: "TOML configuration file", 56 } 57 ) 58 59 // These settings ensure that TOML keys use the same names as Go struct fields. 60 var tomlSettings = toml.Config{ 61 NormFieldName: func(rt reflect.Type, key string) string { 62 return key 63 }, 64 FieldToKey: func(rt reflect.Type, field string) string { 65 return field 66 }, 67 MissingField: func(rt reflect.Type, field string) error { 68 link := "" 69 if unicode.IsUpper(rune(rt.Name()[0])) && rt.PkgPath() != "main" { 70 link = fmt.Sprintf(", see https://godoc.org/%s#%s for available fields", rt.PkgPath(), rt.Name()) 71 } 72 return fmt.Errorf("field '%s' is not defined in %s%s", field, rt.String(), link) 73 }, 74 } 75 76 type ethstatsConfig struct { 77 URL string `toml:",omitempty"` 78 } 79 80 type gethConfig struct { 81 Eth eth.Config 82 Shh whisper.Config 83 Node node.Config 84 Ethstats ethstatsConfig 85 Dashboard dashboard.Config 86 } 87 88 func loadConfig(file string, cfg *gethConfig) error { 89 f, err := os.Open(file) 90 if err != nil { 91 return err 92 } 93 defer f.Close() 94 95 err = tomlSettings.NewDecoder(bufio.NewReader(f)).Decode(cfg) 96 // Add file name to errors that have a line number. 97 if _, ok := err.(*toml.LineError); ok { 98 err = errors.New(file + ", " + err.Error()) 99 } 100 return err 101 } 102 103 func defaultNodeConfig() node.Config { 104 cfg := node.DefaultConfig 105 cfg.Name = clientIdentifier 106 cfg.Version = params.VersionWithCommit(gitCommit) 107 cfg.HTTPModules = append(cfg.HTTPModules, "eth", "shh") 108 cfg.WSModules = append(cfg.WSModules, "eth", "shh") 109 cfg.IPCPath = "geth.ipc" 110 return cfg 111 } 112 113 func makeConfigNode(ctx *cli.Context) (*node.Node, gethConfig) { 114 // Load defaults. 115 cfg := gethConfig{ 116 Eth: eth.DefaultConfig, 117 Shh: whisper.DefaultConfig, 118 Node: defaultNodeConfig(), 119 Dashboard: dashboard.DefaultConfig, 120 } 121 122 // Load config file. 123 if file := ctx.GlobalString(configFileFlag.Name); file != "" { 124 if err := loadConfig(file, &cfg); err != nil { 125 utils.Fatalf("%v", err) 126 } 127 } 128 129 // Apply flags. 130 utils.SetNodeConfig(ctx, &cfg.Node) 131 stack, err := node.New(&cfg.Node) 132 if err != nil { 133 utils.Fatalf("Failed to create the protocol stack: %v", err) 134 } 135 utils.SetEthConfig(ctx, stack, &cfg.Eth) 136 if ctx.GlobalIsSet(utils.EthStatsURLFlag.Name) { 137 cfg.Ethstats.URL = ctx.GlobalString(utils.EthStatsURLFlag.Name) 138 } 139 140 utils.SetShhConfig(ctx, stack, &cfg.Shh) 141 cfg.Eth.RaftMode = ctx.GlobalBool(utils.RaftModeFlag.Name) 142 utils.SetDashboardConfig(ctx, &cfg.Dashboard) 143 144 return stack, cfg 145 } 146 147 // enableWhisper returns true in case one of the whisper flags is set. 148 func enableWhisper(ctx *cli.Context) bool { 149 for _, flag := range whisperFlags { 150 if ctx.GlobalIsSet(flag.GetName()) { 151 return true 152 } 153 } 154 return false 155 } 156 157 func makeFullNode(ctx *cli.Context) *node.Node { 158 stack, cfg := makeConfigNode(ctx) 159 160 ethChan := utils.RegisterEthService(stack, &cfg.Eth) 161 162 if cfg.Node.IsPermissionEnabled() { 163 utils.RegisterPermissionService(ctx, stack) 164 } 165 166 if ctx.GlobalBool(utils.RaftModeFlag.Name) { 167 RegisterRaftService(stack, ctx, cfg, ethChan) 168 } 169 170 if ctx.GlobalBool(utils.DashboardEnabledFlag.Name) { 171 utils.RegisterDashboardService(stack, &cfg.Dashboard, gitCommit) 172 } 173 174 // Whisper must be explicitly enabled by specifying at least 1 whisper flag or in dev mode 175 shhEnabled := enableWhisper(ctx) 176 shhAutoEnabled := !ctx.GlobalIsSet(utils.WhisperEnabledFlag.Name) && ctx.GlobalIsSet(utils.DeveloperFlag.Name) 177 if shhEnabled || shhAutoEnabled { 178 if ctx.GlobalIsSet(utils.WhisperMaxMessageSizeFlag.Name) { 179 cfg.Shh.MaxMessageSize = uint32(ctx.Int(utils.WhisperMaxMessageSizeFlag.Name)) 180 } 181 if ctx.GlobalIsSet(utils.WhisperMinPOWFlag.Name) { 182 cfg.Shh.MinimumAcceptedPOW = ctx.Float64(utils.WhisperMinPOWFlag.Name) 183 } 184 if ctx.GlobalIsSet(utils.WhisperRestrictConnectionBetweenLightClientsFlag.Name) { 185 cfg.Shh.RestrictConnectionBetweenLightClients = true 186 } 187 utils.RegisterShhService(stack, &cfg.Shh) 188 } 189 190 // Add the Ethereum Stats daemon if requested. 191 if cfg.Ethstats.URL != "" { 192 utils.RegisterEthStatsService(stack, cfg.Ethstats.URL) 193 } 194 return stack 195 } 196 197 // dumpConfig is the dumpconfig command. 198 func dumpConfig(ctx *cli.Context) error { 199 _, cfg := makeConfigNode(ctx) 200 comment := "" 201 202 if cfg.Eth.Genesis != nil { 203 cfg.Eth.Genesis = nil 204 comment += "# Note: this config doesn't contain the genesis block.\n\n" 205 } 206 207 out, err := tomlSettings.Marshal(&cfg) 208 if err != nil { 209 return err 210 } 211 io.WriteString(os.Stdout, comment) 212 os.Stdout.Write(out) 213 return nil 214 } 215 216 func RegisterRaftService(stack *node.Node, ctx *cli.Context, cfg gethConfig, ethChan <-chan *eth.Ethereum) { 217 blockTimeMillis := ctx.GlobalInt(utils.RaftBlockTimeFlag.Name) 218 datadir := ctx.GlobalString(utils.DataDirFlag.Name) 219 joinExistingId := ctx.GlobalInt(utils.RaftJoinExistingFlag.Name) 220 useDns := ctx.GlobalBool(utils.RaftDNSEnabledFlag.Name) 221 raftPort := uint16(ctx.GlobalInt(utils.RaftPortFlag.Name)) 222 223 if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { 224 privkey := cfg.Node.NodeKey() 225 strId := enode.PubkeyToIDV4(&privkey.PublicKey).String() 226 blockTimeNanos := time.Duration(blockTimeMillis) * time.Millisecond 227 peers := cfg.Node.StaticNodes() 228 229 var myId uint16 230 var joinExisting bool 231 232 if joinExistingId > 0 { 233 myId = uint16(joinExistingId) 234 joinExisting = true 235 } else if len(peers) == 0 { 236 utils.Fatalf("Raft-based consensus requires either (1) an initial peers list (in static-nodes.json) including this enode hash (%v), or (2) the flag --raftjoinexisting RAFT_ID, where RAFT_ID has been issued by an existing cluster member calling `raft.addPeer(ENODE_ID)` with an enode ID containing this node's enode hash.", strId) 237 } else { 238 peerIds := make([]string, len(peers)) 239 240 for peerIdx, peer := range peers { 241 if !peer.HasRaftPort() { 242 utils.Fatalf("raftport querystring parameter not specified in static-node enode ID: %v. please check your static-nodes.json file.", peer.String()) 243 } 244 245 peerId := peer.ID().String() 246 peerIds[peerIdx] = peerId 247 if peerId == strId { 248 myId = uint16(peerIdx) + 1 249 } 250 } 251 252 if myId == 0 { 253 utils.Fatalf("failed to find local enode ID (%v) amongst peer IDs: %v", strId, peerIds) 254 } 255 } 256 257 ethereum := <-ethChan 258 return raft.New(ctx, ethereum.ChainConfig(), myId, raftPort, joinExisting, blockTimeNanos, ethereum, peers, datadir, useDns) 259 }); err != nil { 260 utils.Fatalf("Failed to register the Raft service: %v", err) 261 } 262 263 } 264 265 // quorumValidateConsensus checks if a consensus was used. The node is killed if consensus was not used 266 func quorumValidateConsensus(stack *node.Node, isRaft bool) { 267 var ethereum *eth.Ethereum 268 269 err := stack.Service(ðereum) 270 if err != nil { 271 utils.Fatalf("Error retrieving Ethereum service: %v", err) 272 } 273 274 if !isRaft && ethereum.ChainConfig().Istanbul == nil && ethereum.ChainConfig().Clique == nil { 275 utils.Fatalf("Consensus not specified. Exiting!!") 276 } 277 } 278 279 // quorumValidatePrivateTransactionManager returns whether the "PRIVATE_CONFIG" 280 // environment variable is set 281 func quorumValidatePrivateTransactionManager() bool { 282 return os.Getenv("PRIVATE_CONFIG") != "" 283 }