github.com/theQRL/go-zond@v0.1.1/cmd/gzond/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 "os" 24 "reflect" 25 "runtime" 26 "strings" 27 "unicode" 28 29 "github.com/naoina/toml" 30 "github.com/theQRL/go-zond/accounts" 31 "github.com/theQRL/go-zond/accounts/external" 32 "github.com/theQRL/go-zond/accounts/keystore" 33 "github.com/theQRL/go-zond/accounts/scwallet" 34 "github.com/theQRL/go-zond/accounts/usbwallet" 35 "github.com/theQRL/go-zond/cmd/utils" 36 "github.com/theQRL/go-zond/internal/ethapi" 37 "github.com/theQRL/go-zond/internal/flags" 38 "github.com/theQRL/go-zond/internal/version" 39 "github.com/theQRL/go-zond/log" 40 "github.com/theQRL/go-zond/metrics" 41 "github.com/theQRL/go-zond/node" 42 "github.com/theQRL/go-zond/params" 43 "github.com/theQRL/go-zond/zond/catalyst" 44 "github.com/theQRL/go-zond/zond/downloader" 45 "github.com/theQRL/go-zond/zond/ethconfig" 46 "github.com/urfave/cli/v2" 47 ) 48 49 var ( 50 dumpConfigCommand = &cli.Command{ 51 Action: dumpConfig, 52 Name: "dumpconfig", 53 Usage: "Export configuration values in a TOML format", 54 ArgsUsage: "<dumpfile (optional)>", 55 Flags: flags.Merge(nodeFlags, rpcFlags), 56 Description: `Export configuration values in TOML format (to stdout by default).`, 57 } 58 59 configFileFlag = &cli.StringFlag{ 60 Name: "config", 61 Usage: "TOML configuration file", 62 Category: flags.EthCategory, 63 } 64 ) 65 66 // These settings ensure that TOML keys use the same names as Go struct fields. 67 var tomlSettings = toml.Config{ 68 NormFieldName: func(rt reflect.Type, key string) string { 69 return key 70 }, 71 FieldToKey: func(rt reflect.Type, field string) string { 72 return field 73 }, 74 MissingField: func(rt reflect.Type, field string) error { 75 id := fmt.Sprintf("%s.%s", rt.String(), field) 76 if deprecated(id) { 77 log.Warn("Config field is deprecated and won't have an effect", "name", id) 78 return nil 79 } 80 var link string 81 if unicode.IsUpper(rune(rt.Name()[0])) && rt.PkgPath() != "main" { 82 link = fmt.Sprintf(", see https://godoc.org/%s#%s for available fields", rt.PkgPath(), rt.Name()) 83 } 84 return fmt.Errorf("field '%s' is not defined in %s%s", field, rt.String(), link) 85 }, 86 } 87 88 type ethstatsConfig struct { 89 URL string `toml:",omitempty"` 90 } 91 92 type gethConfig struct { 93 Eth ethconfig.Config 94 Node node.Config 95 Ethstats ethstatsConfig 96 Metrics metrics.Config 97 } 98 99 func loadConfig(file string, cfg *gethConfig) error { 100 f, err := os.Open(file) 101 if err != nil { 102 return err 103 } 104 defer f.Close() 105 106 err = tomlSettings.NewDecoder(bufio.NewReader(f)).Decode(cfg) 107 // Add file name to errors that have a line number. 108 if _, ok := err.(*toml.LineError); ok { 109 err = errors.New(file + ", " + err.Error()) 110 } 111 return err 112 } 113 114 func defaultNodeConfig() node.Config { 115 git, _ := version.VCS() 116 cfg := node.DefaultConfig 117 cfg.Name = clientIdentifier 118 cfg.Version = params.VersionWithCommit(git.Commit, git.Date) 119 cfg.HTTPModules = append(cfg.HTTPModules, "zond") 120 cfg.WSModules = append(cfg.WSModules, "zond") 121 cfg.IPCPath = "gzond.ipc" 122 return cfg 123 } 124 125 // loadBaseConfig loads the gethConfig based on the given command line 126 // parameters and config file. 127 func loadBaseConfig(ctx *cli.Context) gethConfig { 128 // Load defaults. 129 cfg := gethConfig{ 130 Eth: ethconfig.Defaults, 131 Node: defaultNodeConfig(), 132 Metrics: metrics.DefaultConfig, 133 } 134 135 // Load config file. 136 if file := ctx.String(configFileFlag.Name); file != "" { 137 if err := loadConfig(file, &cfg); err != nil { 138 utils.Fatalf("%v", err) 139 } 140 } 141 142 // Apply flags. 143 utils.SetNodeConfig(ctx, &cfg.Node) 144 return cfg 145 } 146 147 // makeConfigNode loads geth configuration and creates a blank node instance. 148 func makeConfigNode(ctx *cli.Context) (*node.Node, gethConfig) { 149 cfg := loadBaseConfig(ctx) 150 stack, err := node.New(&cfg.Node) 151 if err != nil { 152 utils.Fatalf("Failed to create the protocol stack: %v", err) 153 } 154 // Node doesn't by default populate account manager backends 155 if err := setAccountManagerBackends(stack.Config(), stack.AccountManager(), stack.KeyStoreDir()); err != nil { 156 utils.Fatalf("Failed to set account manager backends: %v", err) 157 } 158 159 utils.SetEthConfig(ctx, stack, &cfg.Eth) 160 if ctx.IsSet(utils.EthStatsURLFlag.Name) { 161 cfg.Ethstats.URL = ctx.String(utils.EthStatsURLFlag.Name) 162 } 163 applyMetricConfig(ctx, &cfg) 164 165 return stack, cfg 166 } 167 168 // makeFullNode loads geth configuration and creates the Ethereum backend. 169 func makeFullNode(ctx *cli.Context) (*node.Node, ethapi.Backend) { 170 stack, cfg := makeConfigNode(ctx) 171 if ctx.IsSet(utils.OverrideCancun.Name) { 172 v := ctx.Uint64(utils.OverrideCancun.Name) 173 cfg.Eth.OverrideCancun = &v 174 } 175 if ctx.IsSet(utils.OverrideVerkle.Name) { 176 v := ctx.Uint64(utils.OverrideVerkle.Name) 177 cfg.Eth.OverrideVerkle = &v 178 } 179 backend, eth := utils.RegisterEthService(stack, &cfg.Eth) 180 181 // Create gauge with geth system and build information 182 if eth != nil { // The 'eth' backend may be nil in light mode 183 var protos []string 184 for _, p := range eth.Protocols() { 185 protos = append(protos, fmt.Sprintf("%v/%d", p.Name, p.Version)) 186 } 187 metrics.NewRegisteredGaugeInfo("geth/info", nil).Update(metrics.GaugeInfoValue{ 188 "arch": runtime.GOARCH, 189 "os": runtime.GOOS, 190 "version": cfg.Node.Version, 191 "protocols": strings.Join(protos, ","), 192 }) 193 } 194 195 // Configure log filter RPC API. 196 filterSystem := utils.RegisterFilterAPI(stack, backend, &cfg.Eth) 197 198 // Configure GraphQL if requested. 199 if ctx.IsSet(utils.GraphQLEnabledFlag.Name) { 200 utils.RegisterGraphQLService(stack, backend, filterSystem, &cfg.Node) 201 } 202 203 // Add the Ethereum Stats daemon if requested. 204 if cfg.Ethstats.URL != "" { 205 utils.RegisterEthStatsService(stack, backend, cfg.Ethstats.URL) 206 } 207 208 // Configure full-sync tester service if requested 209 if ctx.IsSet(utils.SyncTargetFlag.Name) && cfg.Eth.SyncMode == downloader.FullSync { 210 utils.RegisterFullSyncTester(stack, eth, ctx.Path(utils.SyncTargetFlag.Name)) 211 } 212 213 // Start the dev mode if requested, or launch the engine API for 214 // interacting with external consensus client. 215 if ctx.IsSet(utils.DeveloperFlag.Name) { 216 simBeacon, err := catalyst.NewSimulatedBeacon(ctx.Uint64(utils.DeveloperPeriodFlag.Name), eth) 217 if err != nil { 218 utils.Fatalf("failed to register dev mode catalyst service: %v", err) 219 } 220 catalyst.RegisterSimulatedBeaconAPIs(stack, simBeacon) 221 stack.RegisterLifecycle(simBeacon) 222 } else if cfg.Eth.SyncMode != downloader.LightSync { 223 err := catalyst.Register(stack, eth) 224 if err != nil { 225 utils.Fatalf("failed to register catalyst service: %v", err) 226 } 227 } 228 return stack, backend 229 } 230 231 // dumpConfig is the dumpconfig command. 232 func dumpConfig(ctx *cli.Context) error { 233 _, cfg := makeConfigNode(ctx) 234 comment := "" 235 236 if cfg.Eth.Genesis != nil { 237 cfg.Eth.Genesis = nil 238 comment += "# Note: this config doesn't contain the genesis block.\n\n" 239 } 240 241 out, err := tomlSettings.Marshal(&cfg) 242 if err != nil { 243 return err 244 } 245 246 dump := os.Stdout 247 if ctx.NArg() > 0 { 248 dump, err = os.OpenFile(ctx.Args().Get(0), os.O_RDWR|os.O_CREATE|os.O_TRUNC, 0644) 249 if err != nil { 250 return err 251 } 252 defer dump.Close() 253 } 254 dump.WriteString(comment) 255 dump.Write(out) 256 257 return nil 258 } 259 260 func applyMetricConfig(ctx *cli.Context, cfg *gethConfig) { 261 if ctx.IsSet(utils.MetricsEnabledFlag.Name) { 262 cfg.Metrics.Enabled = ctx.Bool(utils.MetricsEnabledFlag.Name) 263 } 264 if ctx.IsSet(utils.MetricsEnabledExpensiveFlag.Name) { 265 cfg.Metrics.EnabledExpensive = ctx.Bool(utils.MetricsEnabledExpensiveFlag.Name) 266 } 267 if ctx.IsSet(utils.MetricsHTTPFlag.Name) { 268 cfg.Metrics.HTTP = ctx.String(utils.MetricsHTTPFlag.Name) 269 } 270 if ctx.IsSet(utils.MetricsPortFlag.Name) { 271 cfg.Metrics.Port = ctx.Int(utils.MetricsPortFlag.Name) 272 } 273 if ctx.IsSet(utils.MetricsEnableInfluxDBFlag.Name) { 274 cfg.Metrics.EnableInfluxDB = ctx.Bool(utils.MetricsEnableInfluxDBFlag.Name) 275 } 276 if ctx.IsSet(utils.MetricsInfluxDBEndpointFlag.Name) { 277 cfg.Metrics.InfluxDBEndpoint = ctx.String(utils.MetricsInfluxDBEndpointFlag.Name) 278 } 279 if ctx.IsSet(utils.MetricsInfluxDBDatabaseFlag.Name) { 280 cfg.Metrics.InfluxDBDatabase = ctx.String(utils.MetricsInfluxDBDatabaseFlag.Name) 281 } 282 if ctx.IsSet(utils.MetricsInfluxDBUsernameFlag.Name) { 283 cfg.Metrics.InfluxDBUsername = ctx.String(utils.MetricsInfluxDBUsernameFlag.Name) 284 } 285 if ctx.IsSet(utils.MetricsInfluxDBPasswordFlag.Name) { 286 cfg.Metrics.InfluxDBPassword = ctx.String(utils.MetricsInfluxDBPasswordFlag.Name) 287 } 288 if ctx.IsSet(utils.MetricsInfluxDBTagsFlag.Name) { 289 cfg.Metrics.InfluxDBTags = ctx.String(utils.MetricsInfluxDBTagsFlag.Name) 290 } 291 if ctx.IsSet(utils.MetricsEnableInfluxDBV2Flag.Name) { 292 cfg.Metrics.EnableInfluxDBV2 = ctx.Bool(utils.MetricsEnableInfluxDBV2Flag.Name) 293 } 294 if ctx.IsSet(utils.MetricsInfluxDBTokenFlag.Name) { 295 cfg.Metrics.InfluxDBToken = ctx.String(utils.MetricsInfluxDBTokenFlag.Name) 296 } 297 if ctx.IsSet(utils.MetricsInfluxDBBucketFlag.Name) { 298 cfg.Metrics.InfluxDBBucket = ctx.String(utils.MetricsInfluxDBBucketFlag.Name) 299 } 300 if ctx.IsSet(utils.MetricsInfluxDBOrganizationFlag.Name) { 301 cfg.Metrics.InfluxDBOrganization = ctx.String(utils.MetricsInfluxDBOrganizationFlag.Name) 302 } 303 } 304 305 func deprecated(field string) bool { 306 switch field { 307 case "ethconfig.Config.EVMInterpreter": 308 return true 309 case "ethconfig.Config.EWASMInterpreter": 310 return true 311 case "ethconfig.Config.TrieCleanCacheJournal": 312 return true 313 case "ethconfig.Config.TrieCleanCacheRejournal": 314 return true 315 default: 316 return false 317 } 318 } 319 320 func setAccountManagerBackends(conf *node.Config, am *accounts.Manager, keydir string) error { 321 scryptN := keystore.StandardScryptN 322 scryptP := keystore.StandardScryptP 323 if conf.UseLightweightKDF { 324 scryptN = keystore.LightScryptN 325 scryptP = keystore.LightScryptP 326 } 327 328 // Assemble the supported backends 329 if len(conf.ExternalSigner) > 0 { 330 log.Info("Using external signer", "url", conf.ExternalSigner) 331 if extBackend, err := external.NewExternalBackend(conf.ExternalSigner); err == nil { 332 am.AddBackend(extBackend) 333 return nil 334 } else { 335 return fmt.Errorf("error connecting to external signer: %v", err) 336 } 337 } 338 339 // For now, we're using EITHER external signer OR local signers. 340 // If/when we implement some form of lockfile for USB and keystore wallets, 341 // we can have both, but it's very confusing for the user to see the same 342 // accounts in both externally and locally, plus very racey. 343 am.AddBackend(keystore.NewKeyStore(keydir, scryptN, scryptP)) 344 if conf.USB { 345 // Start a USB hub for Ledger hardware wallets 346 if ledgerhub, err := usbwallet.NewLedgerHub(); err != nil { 347 log.Warn(fmt.Sprintf("Failed to start Ledger hub, disabling: %v", err)) 348 } else { 349 am.AddBackend(ledgerhub) 350 } 351 // Start a USB hub for Trezor hardware wallets (HID version) 352 if trezorhub, err := usbwallet.NewTrezorHubWithHID(); err != nil { 353 log.Warn(fmt.Sprintf("Failed to start HID Trezor hub, disabling: %v", err)) 354 } else { 355 am.AddBackend(trezorhub) 356 } 357 // Start a USB hub for Trezor hardware wallets (WebUSB version) 358 if trezorhub, err := usbwallet.NewTrezorHubWithWebUSB(); err != nil { 359 log.Warn(fmt.Sprintf("Failed to start WebUSB Trezor hub, disabling: %v", err)) 360 } else { 361 am.AddBackend(trezorhub) 362 } 363 } 364 if len(conf.SmartCardDaemonPath) > 0 { 365 // Start a smart card hub 366 if schub, err := scwallet.NewHub(conf.SmartCardDaemonPath, scwallet.Scheme, keydir); err != nil { 367 log.Warn(fmt.Sprintf("Failed to start smart card hub, disabling: %v", err)) 368 } else { 369 am.AddBackend(schub) 370 } 371 } 372 373 return nil 374 }