github.com/pfcoder/quorum@v2.0.3-0.20180501191142-d4a1b0958135+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 "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/p2p/discover" 36 "github.com/ethereum/go-ethereum/params" 37 "github.com/ethereum/go-ethereum/raft" 38 whisper "github.com/ethereum/go-ethereum/whisper/whisperv5" 39 "github.com/naoina/toml" 40 "time" 41 ) 42 43 var ( 44 dumpConfigCommand = cli.Command{ 45 Action: utils.MigrateFlags(dumpConfig), 46 Name: "dumpconfig", 47 Usage: "Show configuration values", 48 ArgsUsage: "", 49 Flags: append(append(nodeFlags, rpcFlags...), whisperFlags...), 50 Category: "MISCELLANEOUS COMMANDS", 51 Description: `The dumpconfig command shows configuration values.`, 52 } 53 54 configFileFlag = cli.StringFlag{ 55 Name: "config", 56 Usage: "TOML configuration file", 57 } 58 ) 59 60 // These settings ensure that TOML keys use the same names as Go struct fields. 61 var tomlSettings = toml.Config{ 62 NormFieldName: func(rt reflect.Type, key string) string { 63 return key 64 }, 65 FieldToKey: func(rt reflect.Type, field string) string { 66 return field 67 }, 68 MissingField: func(rt reflect.Type, field string) error { 69 link := "" 70 if unicode.IsUpper(rune(rt.Name()[0])) && rt.PkgPath() != "main" { 71 link = fmt.Sprintf(", see https://godoc.org/%s#%s for available fields", rt.PkgPath(), rt.Name()) 72 } 73 return fmt.Errorf("field '%s' is not defined in %s%s", field, rt.String(), link) 74 }, 75 } 76 77 type ethstatsConfig struct { 78 URL string `toml:",omitempty"` 79 } 80 81 type gethConfig struct { 82 Eth eth.Config 83 Shh whisper.Config 84 Node node.Config 85 Ethstats ethstatsConfig 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 } 120 121 // Load config file. 122 if file := ctx.GlobalString(configFileFlag.Name); file != "" { 123 if err := loadConfig(file, &cfg); err != nil { 124 utils.Fatalf("%v", err) 125 } 126 } 127 128 // Apply flags. 129 utils.SetNodeConfig(ctx, &cfg.Node) 130 stack, err := node.New(&cfg.Node) 131 if err != nil { 132 utils.Fatalf("Failed to create the protocol stack: %v", err) 133 } 134 utils.SetEthConfig(ctx, stack, &cfg.Eth) 135 if ctx.GlobalIsSet(utils.EthStatsURLFlag.Name) { 136 cfg.Ethstats.URL = ctx.GlobalString(utils.EthStatsURLFlag.Name) 137 } 138 139 utils.SetShhConfig(ctx, stack, &cfg.Shh) 140 cfg.Eth.RaftMode = ctx.GlobalBool(utils.RaftModeFlag.Name) 141 142 return stack, cfg 143 } 144 145 // enableWhisper returns true in case one of the whisper flags is set. 146 func enableWhisper(ctx *cli.Context) bool { 147 for _, flag := range whisperFlags { 148 if ctx.GlobalIsSet(flag.GetName()) { 149 return true 150 } 151 } 152 return false 153 } 154 155 func makeFullNode(ctx *cli.Context) *node.Node { 156 stack, cfg := makeConfigNode(ctx) 157 158 ethChan := utils.RegisterEthService(stack, &cfg.Eth) 159 160 if ctx.GlobalBool(utils.RaftModeFlag.Name) { 161 RegisterRaftService(stack, ctx, cfg, ethChan) 162 } 163 164 // Whisper must be explicitly enabled by specifying at least 1 whisper flag or in dev mode 165 shhEnabled := enableWhisper(ctx) 166 shhAutoEnabled := !ctx.GlobalIsSet(utils.WhisperEnabledFlag.Name) && ctx.GlobalIsSet(utils.DevModeFlag.Name) 167 if shhEnabled || shhAutoEnabled { 168 if ctx.GlobalIsSet(utils.WhisperMaxMessageSizeFlag.Name) { 169 cfg.Shh.MaxMessageSize = uint32(ctx.Int(utils.WhisperMaxMessageSizeFlag.Name)) 170 } 171 if ctx.GlobalIsSet(utils.WhisperMinPOWFlag.Name) { 172 cfg.Shh.MinimumAcceptedPOW = ctx.Float64(utils.WhisperMinPOWFlag.Name) 173 } 174 utils.RegisterShhService(stack, &cfg.Shh) 175 } 176 177 // Add the Ethereum Stats daemon if requested. 178 if cfg.Ethstats.URL != "" { 179 utils.RegisterEthStatsService(stack, cfg.Ethstats.URL) 180 } 181 182 // Add the release oracle service so it boots along with node. 183 if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { 184 config := release.Config{ 185 Oracle: relOracle, 186 Major: uint32(params.VersionMajor), 187 Minor: uint32(params.VersionMinor), 188 Patch: uint32(params.VersionPatch), 189 } 190 commit, _ := hex.DecodeString(gitCommit) 191 copy(config.Commit[:], commit) 192 return release.NewReleaseService(ctx, config) 193 }); err != nil { 194 utils.Fatalf("Failed to register the Geth release oracle service: %v", err) 195 } 196 return stack 197 } 198 199 // dumpConfig is the dumpconfig command. 200 func dumpConfig(ctx *cli.Context) error { 201 _, cfg := makeConfigNode(ctx) 202 comment := "" 203 204 if cfg.Eth.Genesis != nil { 205 cfg.Eth.Genesis = nil 206 comment += "# Note: this config doesn't contain the genesis block.\n\n" 207 } 208 209 out, err := tomlSettings.Marshal(&cfg) 210 if err != nil { 211 return err 212 } 213 io.WriteString(os.Stdout, comment) 214 os.Stdout.Write(out) 215 return nil 216 } 217 218 func RegisterRaftService(stack *node.Node, ctx *cli.Context, cfg gethConfig, ethChan <-chan *eth.Ethereum) { 219 blockTimeMillis := ctx.GlobalInt(utils.RaftBlockTimeFlag.Name) 220 datadir := ctx.GlobalString(utils.DataDirFlag.Name) 221 joinExistingId := ctx.GlobalInt(utils.RaftJoinExistingFlag.Name) 222 223 raftPort := uint16(ctx.GlobalInt(utils.RaftPortFlag.Name)) 224 225 if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { 226 privkey := cfg.Node.NodeKey() 227 strId := discover.PubkeyID(&privkey.PublicKey).String() 228 blockTimeNanos := time.Duration(blockTimeMillis) * time.Millisecond 229 peers := cfg.Node.StaticNodes() 230 231 var myId uint16 232 var joinExisting bool 233 234 if joinExistingId > 0 { 235 myId = uint16(joinExistingId) 236 joinExisting = true 237 } else if len(peers) == 0 { 238 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) 239 } else { 240 peerIds := make([]string, len(peers)) 241 242 for peerIdx, peer := range peers { 243 if !peer.HasRaftPort() { 244 utils.Fatalf("raftport querystring parameter not specified in static-node enode ID: %v. please check your static-nodes.json file.", peer.String()) 245 } 246 247 peerId := peer.ID.String() 248 peerIds[peerIdx] = peerId 249 if peerId == strId { 250 myId = uint16(peerIdx) + 1 251 } 252 } 253 254 if myId == 0 { 255 utils.Fatalf("failed to find local enode ID (%v) amongst peer IDs: %v", strId, peerIds) 256 } 257 } 258 259 ethereum := <-ethChan 260 261 return raft.New(ctx, ethereum.ChainConfig(), myId, raftPort, joinExisting, blockTimeNanos, ethereum, peers, datadir) 262 }); err != nil { 263 utils.Fatalf("Failed to register the Raft service: %v", err) 264 } 265 266 }