github.com/bigzoro/my_simplechain@v0.0.0-20240315012955-8ad0a2a29bb9/cmd/utils/flags.go (about) 1 // Copyright 2015 The go-simplechain Authors 2 // This file is part of go-simplechain. 3 // 4 // go-simplechain 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-simplechain 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-simplechain. If not, see <http://www.gnu.org/licenses/>. 16 17 // Package utils contains internal helper functions for go-simplechain commands. 18 package utils 19 20 import ( 21 "crypto/ecdsa" 22 "encoding/binary" 23 "errors" 24 "fmt" 25 "io" 26 "io/ioutil" 27 "math/big" 28 "os" 29 "path/filepath" 30 "strconv" 31 "strings" 32 "text/tabwriter" 33 "text/template" 34 "time" 35 36 "github.com/bigzoro/my_simplechain/accounts" 37 "github.com/bigzoro/my_simplechain/accounts/keystore" 38 "github.com/bigzoro/my_simplechain/common" 39 "github.com/bigzoro/my_simplechain/common/fdlimit" 40 "github.com/bigzoro/my_simplechain/consensus" 41 "github.com/bigzoro/my_simplechain/consensus/clique" 42 "github.com/bigzoro/my_simplechain/consensus/ethash" 43 bls "github.com/bigzoro/my_simplechain/consensus/hotstuff/bls12-381" 44 "github.com/bigzoro/my_simplechain/consensus/pbft" 45 "github.com/bigzoro/my_simplechain/core" 46 "github.com/bigzoro/my_simplechain/core/vm" 47 "github.com/bigzoro/my_simplechain/crypto" 48 "github.com/bigzoro/my_simplechain/eth" 49 "github.com/bigzoro/my_simplechain/eth/downloader" 50 "github.com/bigzoro/my_simplechain/eth/gasprice" 51 "github.com/bigzoro/my_simplechain/ethdb" 52 "github.com/bigzoro/my_simplechain/ethstats" 53 "github.com/bigzoro/my_simplechain/graphql" 54 "github.com/bigzoro/my_simplechain/les" 55 "github.com/bigzoro/my_simplechain/log" 56 "github.com/bigzoro/my_simplechain/metrics" 57 "github.com/bigzoro/my_simplechain/metrics/influxdb" 58 "github.com/bigzoro/my_simplechain/miner" 59 "github.com/bigzoro/my_simplechain/node" 60 "github.com/bigzoro/my_simplechain/p2p" 61 "github.com/bigzoro/my_simplechain/p2p/discv5" 62 "github.com/bigzoro/my_simplechain/p2p/enode" 63 "github.com/bigzoro/my_simplechain/p2p/nat" 64 "github.com/bigzoro/my_simplechain/p2p/netutil" 65 "github.com/bigzoro/my_simplechain/params" 66 "github.com/bigzoro/my_simplechain/permission" 67 "github.com/bigzoro/my_simplechain/rpc" 68 whisper "github.com/bigzoro/my_simplechain/whisper/whisperv6" 69 "gopkg.in/urfave/cli.v1" 70 ) 71 72 var ( 73 CommandHelpTemplate = `{{.cmd.Name}}{{if .cmd.Subcommands}} command{{end}}{{if .cmd.Flags}} [command options]{{end}} [arguments...] 74 {{if .cmd.Description}}{{.cmd.Description}} 75 {{end}}{{if .cmd.Subcommands}} 76 SUBCOMMANDS: 77 {{range .cmd.Subcommands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}} 78 {{end}}{{end}}{{if .categorizedFlags}} 79 {{range $idx, $categorized := .categorizedFlags}}{{$categorized.Name}} OPTIONS: 80 {{range $categorized.Flags}}{{"\t"}}{{.}} 81 {{end}} 82 {{end}}{{end}}` 83 84 OriginCommandHelpTemplate = `{{.Name}}{{if .Subcommands}} command{{end}}{{if .Flags}} [command options]{{end}} [arguments...] 85 {{if .Description}}{{.Description}} 86 {{end}}{{if .Subcommands}} 87 SUBCOMMANDS: 88 {{range .Subcommands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}} 89 {{end}}{{end}}{{if .Flags}} 90 OPTIONS: 91 {{range $.Flags}}{{"\t"}}{{.}} 92 {{end}} 93 {{end}}` 94 ) 95 96 func init() { 97 cli.AppHelpTemplate = `{{.Name}} {{if .Flags}}[global options] {{end}}command{{if .Flags}} [command options]{{end}} [arguments...] 98 99 VERSION: 100 {{.Version}} 101 102 COMMANDS: 103 {{range .Commands}}{{.Name}}{{with .ShortName}}, {{.}}{{end}}{{ "\t" }}{{.Usage}} 104 {{end}}{{if .Flags}} 105 GLOBAL OPTIONS: 106 {{range .Flags}}{{.}} 107 {{end}}{{end}} 108 ` 109 cli.CommandHelpTemplate = CommandHelpTemplate 110 cli.HelpPrinter = printHelp 111 } 112 113 // NewApp creates an app with sane defaults. 114 func NewApp(gitCommit, gitDate, usage string) *cli.App { 115 app := cli.NewApp() 116 app.Name = filepath.Base(os.Args[0]) 117 app.Author = "" 118 app.Email = "" 119 app.Version = params.VersionWithCommit(gitCommit, gitDate) 120 app.Usage = usage 121 return app 122 } 123 124 func printHelp(out io.Writer, templ string, data interface{}) { 125 funcMap := template.FuncMap{"join": strings.Join} 126 t := template.Must(template.New("help").Funcs(funcMap).Parse(templ)) 127 w := tabwriter.NewWriter(out, 38, 8, 2, ' ', 0) 128 err := t.Execute(w, data) 129 if err != nil { 130 panic(err) 131 } 132 w.Flush() 133 } 134 135 // These are all the command line flags we support. 136 // If you add to this list, please remember to include the 137 // flag in the appropriate command definition. 138 // 139 // The flags are defined here so their names and help texts 140 // are the same for all commands. 141 142 // MakeDataDir retrieves the currently requested data directory, terminating 143 // if none (or the empty string) is specified. If the node is starting a testnet, 144 // the a subdirectory of the specified datadir will be used. 145 func MakeDataDir(ctx *cli.Context) string { 146 if path := ctx.GlobalString(DataDirFlag.Name); path != "" { 147 if ctx.GlobalBool(TestnetFlag.Name) { 148 return filepath.Join(path, "testnet") 149 } 150 return path 151 } 152 Fatalf("Cannot determine default data directory, please set manually (--datadir)") 153 return "" 154 } 155 156 // setNodeKey creates a node key from set command line flags, either loading it 157 // from a file or as a specified hex value. If neither flags were provided, this 158 // method returns nil and an emphemeral key is to be generated. 159 func setNodeKey(ctx *cli.Context, cfg *p2p.Config) { 160 var ( 161 hex = ctx.GlobalString(NodeKeyHexFlag.Name) 162 file = ctx.GlobalString(NodeKeyFileFlag.Name) 163 key *ecdsa.PrivateKey 164 err error 165 ) 166 switch { 167 case file != "" && hex != "": 168 Fatalf("Options %q and %q are mutually exclusive", NodeKeyFileFlag.Name, NodeKeyHexFlag.Name) 169 case file != "": 170 if key, err = crypto.LoadECDSA(file); err != nil { 171 Fatalf("Option %q: %v", NodeKeyFileFlag.Name, err) 172 } 173 cfg.PrivateKey = key 174 case hex != "": 175 if key, err = crypto.HexToECDSA(hex); err != nil { 176 Fatalf("Option %q: %v", NodeKeyHexFlag.Name, err) 177 } 178 cfg.PrivateKey = key 179 } 180 } 181 182 // setNodeUserIdent creates the user identifier from CLI flags. 183 func setNodeUserIdent(ctx *cli.Context, cfg *node.Config) { 184 if identity := ctx.GlobalString(IdentityFlag.Name); len(identity) > 0 { 185 cfg.UserIdent = identity 186 } 187 } 188 189 // setBootstrapNodes creates a list of bootstrap nodes from the command line 190 // flags, reverting to pre-configured ones if none have been specified. 191 func setBootstrapNodes(ctx *cli.Context, cfg *p2p.Config) { 192 urls := params.MainnetBootnodes 193 switch { 194 case ctx.GlobalIsSet(BootnodesFlag.Name) || ctx.GlobalIsSet(BootnodesV4Flag.Name): 195 if ctx.GlobalIsSet(BootnodesV4Flag.Name) { 196 urls = strings.Split(ctx.GlobalString(BootnodesV4Flag.Name), ",") 197 } else { 198 urls = strings.Split(ctx.GlobalString(BootnodesFlag.Name), ",") 199 } 200 case ctx.GlobalBool(TestnetFlag.Name): 201 urls = params.TestnetBootnodes 202 case cfg.BootstrapNodes != nil: 203 return // already set, don't apply defaults. 204 } 205 206 cfg.BootstrapNodes = make([]*enode.Node, 0, len(urls)) 207 for _, url := range urls { 208 if url != "" { 209 node, err := enode.Parse(enode.ValidSchemes, url) 210 if err != nil { 211 log.Crit("Bootstrap URL invalid", "enode", url, "err", err) 212 continue 213 } 214 cfg.BootstrapNodes = append(cfg.BootstrapNodes, node) 215 } 216 } 217 } 218 219 // setBootstrapNodesV5 creates a list of bootstrap nodes from the command line 220 // flags, reverting to pre-configured ones if none have been specified. 221 func setBootstrapNodesV5(ctx *cli.Context, cfg *p2p.Config) { 222 urls := params.DiscoveryV5Bootnodes 223 switch { 224 case ctx.GlobalIsSet(BootnodesFlag.Name) || ctx.GlobalIsSet(BootnodesV5Flag.Name): 225 if ctx.GlobalIsSet(BootnodesV5Flag.Name) { 226 urls = strings.Split(ctx.GlobalString(BootnodesV5Flag.Name), ",") 227 } else { 228 urls = strings.Split(ctx.GlobalString(BootnodesFlag.Name), ",") 229 } 230 case cfg.BootstrapNodesV5 != nil: 231 return // already set, don't apply defaults. 232 } 233 234 cfg.BootstrapNodesV5 = make([]*discv5.Node, 0, len(urls)) 235 for _, url := range urls { 236 if url != "" { 237 node, err := discv5.ParseNode(url) 238 if err != nil { 239 log.Error("Bootstrap URL invalid", "enode", url, "err", err) 240 continue 241 } 242 cfg.BootstrapNodesV5 = append(cfg.BootstrapNodesV5, node) 243 } 244 } 245 } 246 247 // setListenAddress creates a TCP listening address string from set command 248 // line flags. 249 func setListenAddress(ctx *cli.Context, cfg *p2p.Config) { 250 if ctx.GlobalIsSet(ListenPortFlag.Name) { 251 cfg.ListenAddr = fmt.Sprintf(":%d", ctx.GlobalInt(ListenPortFlag.Name)) 252 } 253 } 254 255 // setNAT creates a port mapper from command line flags. 256 func setNAT(ctx *cli.Context, cfg *p2p.Config) { 257 if ctx.GlobalIsSet(NATFlag.Name) { 258 natif, err := nat.Parse(ctx.GlobalString(NATFlag.Name)) 259 if err != nil { 260 Fatalf("Option %s: %v", NATFlag.Name, err) 261 } 262 cfg.NAT = natif 263 } 264 } 265 266 // splitAndTrim splits input separated by a comma 267 // and trims excessive white space from the substrings. 268 func splitAndTrim(input string) []string { 269 result := strings.Split(input, ",") 270 for i, r := range result { 271 result[i] = strings.TrimSpace(r) 272 } 273 return result 274 } 275 276 // setHTTP creates the HTTP RPC listener interface string from the set 277 // command line flags, returning empty if the HTTP endpoint is disabled. 278 func setHTTP(ctx *cli.Context, cfg *node.Config) { 279 if ctx.GlobalBool(RPCEnabledFlag.Name) && cfg.HTTPHost == "" { 280 cfg.HTTPHost = "127.0.0.1" 281 if ctx.GlobalIsSet(RPCListenAddrFlag.Name) { 282 cfg.HTTPHost = ctx.GlobalString(RPCListenAddrFlag.Name) 283 } 284 } 285 if ctx.GlobalIsSet(RPCPortFlag.Name) { 286 cfg.HTTPPort = ctx.GlobalInt(RPCPortFlag.Name) 287 } 288 if ctx.GlobalIsSet(RPCCORSDomainFlag.Name) { 289 cfg.HTTPCors = splitAndTrim(ctx.GlobalString(RPCCORSDomainFlag.Name)) 290 } 291 if ctx.GlobalIsSet(RPCApiFlag.Name) { 292 cfg.HTTPModules = splitAndTrim(ctx.GlobalString(RPCApiFlag.Name)) 293 } 294 if ctx.GlobalIsSet(RPCVirtualHostsFlag.Name) { 295 cfg.HTTPVirtualHosts = splitAndTrim(ctx.GlobalString(RPCVirtualHostsFlag.Name)) 296 } 297 } 298 299 // setGraphQL creates the GraphQL listener interface string from the set 300 // command line flags, returning empty if the GraphQL endpoint is disabled. 301 func setGraphQL(ctx *cli.Context, cfg *node.Config) { 302 if ctx.GlobalBool(GraphQLEnabledFlag.Name) && cfg.GraphQLHost == "" { 303 cfg.GraphQLHost = "127.0.0.1" 304 if ctx.GlobalIsSet(GraphQLListenAddrFlag.Name) { 305 cfg.GraphQLHost = ctx.GlobalString(GraphQLListenAddrFlag.Name) 306 } 307 } 308 cfg.GraphQLPort = ctx.GlobalInt(GraphQLPortFlag.Name) 309 if ctx.GlobalIsSet(GraphQLCORSDomainFlag.Name) { 310 cfg.GraphQLCors = splitAndTrim(ctx.GlobalString(GraphQLCORSDomainFlag.Name)) 311 } 312 if ctx.GlobalIsSet(GraphQLVirtualHostsFlag.Name) { 313 cfg.GraphQLVirtualHosts = splitAndTrim(ctx.GlobalString(GraphQLVirtualHostsFlag.Name)) 314 } 315 } 316 317 // setWS creates the WebSocket RPC listener interface string from the set 318 // command line flags, returning empty if the HTTP endpoint is disabled. 319 func setWS(ctx *cli.Context, cfg *node.Config) { 320 if ctx.GlobalBool(WSEnabledFlag.Name) && cfg.WSHost == "" { 321 cfg.WSHost = "127.0.0.1" 322 if ctx.GlobalIsSet(WSListenAddrFlag.Name) { 323 cfg.WSHost = ctx.GlobalString(WSListenAddrFlag.Name) 324 } 325 } 326 if ctx.GlobalIsSet(WSPortFlag.Name) { 327 cfg.WSPort = ctx.GlobalInt(WSPortFlag.Name) 328 } 329 if ctx.GlobalIsSet(WSAllowedOriginsFlag.Name) { 330 cfg.WSOrigins = splitAndTrim(ctx.GlobalString(WSAllowedOriginsFlag.Name)) 331 } 332 if ctx.GlobalIsSet(WSApiFlag.Name) { 333 cfg.WSModules = splitAndTrim(ctx.GlobalString(WSApiFlag.Name)) 334 } 335 } 336 337 // setIPC creates an IPC path configuration from the set command line flags, 338 // returning an empty string if IPC was explicitly disabled, or the set path. 339 func setIPC(ctx *cli.Context, cfg *node.Config) { 340 CheckExclusive(ctx, IPCDisabledFlag, IPCPathFlag) 341 switch { 342 case ctx.GlobalBool(IPCDisabledFlag.Name): 343 cfg.IPCPath = "" 344 case ctx.GlobalIsSet(IPCPathFlag.Name): 345 cfg.IPCPath = ctx.GlobalString(IPCPathFlag.Name) 346 } 347 } 348 349 // setLes configures the les server and ultra light client settings from the command line flags. 350 func setLes(ctx *cli.Context, cfg *eth.Config) { 351 if ctx.GlobalIsSet(LightServeFlag.Name) { 352 cfg.LightServ = ctx.GlobalInt(LightServeFlag.Name) 353 } 354 if ctx.GlobalIsSet(LightIngressFlag.Name) { 355 cfg.LightIngress = ctx.GlobalInt(LightIngressFlag.Name) 356 } 357 if ctx.GlobalIsSet(LightEgressFlag.Name) { 358 cfg.LightEgress = ctx.GlobalInt(LightEgressFlag.Name) 359 } 360 if ctx.GlobalIsSet(LightMaxPeersFlag.Name) { 361 cfg.LightPeers = ctx.GlobalInt(LightMaxPeersFlag.Name) 362 } 363 if ctx.GlobalIsSet(UltraLightServersFlag.Name) { 364 cfg.UltraLightServers = strings.Split(ctx.GlobalString(UltraLightServersFlag.Name), ",") 365 } 366 if ctx.GlobalIsSet(UltraLightFractionFlag.Name) { 367 cfg.UltraLightFraction = ctx.GlobalInt(UltraLightFractionFlag.Name) 368 } 369 if cfg.UltraLightFraction <= 0 && cfg.UltraLightFraction > 100 { 370 log.Error("Ultra light fraction is invalid", "had", cfg.UltraLightFraction, "updated", eth.DefaultConfig.UltraLightFraction) 371 cfg.UltraLightFraction = eth.DefaultConfig.UltraLightFraction 372 } 373 if ctx.GlobalIsSet(UltraLightOnlyAnnounceFlag.Name) { 374 cfg.UltraLightOnlyAnnounce = ctx.GlobalBool(UltraLightOnlyAnnounceFlag.Name) 375 } 376 } 377 378 // makeDatabaseHandles raises out the number of allowed file handles per process 379 // for Geth and returns half of the allowance to assign to the database. 380 func makeDatabaseHandles() int { 381 limit, err := fdlimit.Maximum() 382 if err != nil { 383 Fatalf("Failed to retrieve file descriptor allowance: %v", err) 384 } 385 raised, err := fdlimit.Raise(uint64(limit)) 386 if err != nil { 387 Fatalf("Failed to raise file descriptor allowance: %v", err) 388 } 389 return int(raised / 2) // Leave half for networking and other stuff 390 } 391 392 // MakeAddress converts an account specified directly as a hex encoded string or 393 // a key index in the key store to an internal account representation. 394 func MakeAddress(ks *keystore.KeyStore, account string) (accounts.Account, error) { 395 // If the specified account is a valid address, return it 396 if common.IsHexAddress(account) { 397 return accounts.Account{Address: common.HexToAddress(account)}, nil 398 } 399 // Otherwise try to interpret the account as a keystore index 400 index, err := strconv.Atoi(account) 401 if err != nil || index < 0 { 402 return accounts.Account{}, fmt.Errorf("invalid account address or index %q", account) 403 } 404 log.Warn("-------------------------------------------------------------------") 405 log.Warn("Referring to accounts by order in the keystore folder is dangerous!") 406 log.Warn("This functionality is deprecated and will be removed in the future!") 407 log.Warn("Please use explicit addresses! (can search via `geth account list`)") 408 log.Warn("-------------------------------------------------------------------") 409 410 accs := ks.Accounts() 411 if len(accs) <= index { 412 return accounts.Account{}, fmt.Errorf("index %d higher than number of accounts %d", index, len(accs)) 413 } 414 return accs[index], nil 415 } 416 417 // setEtherbase retrieves the etherbase either from the directly specified 418 // command line flags or from the keystore if CLI indexed. 419 func setEtherbase(ctx *cli.Context, ks *keystore.KeyStore, cfg *eth.Config) { 420 // Extract the current etherbase, new flag overriding legacy one 421 var etherbase string 422 if ctx.GlobalIsSet(MinerEtherbaseFlag.Name) { 423 etherbase = ctx.GlobalString(MinerEtherbaseFlag.Name) 424 } 425 // Convert the etherbase into an address and configure it 426 if etherbase != "" { 427 if ks != nil { 428 account, err := MakeAddress(ks, etherbase) 429 if err != nil { 430 Fatalf("Invalid miner etherbase: %v", err) 431 } 432 cfg.Miner.Etherbase = account.Address 433 } else { 434 Fatalf("No etherbase configured") 435 } 436 } 437 } 438 439 // MakePasswordList reads password lines from the file specified by the global --password flag. 440 func MakePasswordList(ctx *cli.Context) []string { 441 path := ctx.GlobalString(PasswordFileFlag.Name) 442 if path == "" { 443 return nil 444 } 445 text, err := ioutil.ReadFile(path) 446 if err != nil { 447 Fatalf("Failed to read password file: %v", err) 448 } 449 lines := strings.Split(string(text), "\n") 450 // Sanitise DOS line endings. 451 for i := range lines { 452 lines[i] = strings.TrimRight(lines[i], "\r") 453 } 454 return lines 455 } 456 457 func SetP2PConfig(ctx *cli.Context, cfg *p2p.Config) { 458 setNodeKey(ctx, cfg) 459 setNAT(ctx, cfg) 460 setListenAddress(ctx, cfg) 461 setBootstrapNodes(ctx, cfg) 462 setBootstrapNodesV5(ctx, cfg) 463 464 lightClient := ctx.GlobalString(SyncModeFlag.Name) == "light" 465 lightServer := ctx.GlobalInt(LightServeFlag.Name) != 0 466 467 lightPeers := ctx.GlobalInt(LightMaxPeersFlag.Name) 468 if ctx.GlobalIsSet(LightMaxPeersFlag.Name) { 469 lightPeers = ctx.GlobalInt(LightMaxPeersFlag.Name) 470 } 471 if lightClient && !ctx.GlobalIsSet(LightMaxPeersFlag.Name) { 472 // dynamic default - for clients we use 1/10th of the default for servers 473 lightPeers /= 10 474 } 475 476 if ctx.GlobalIsSet(MaxPeersFlag.Name) { 477 cfg.MaxPeers = ctx.GlobalInt(MaxPeersFlag.Name) 478 if lightServer && !ctx.GlobalIsSet(LightMaxPeersFlag.Name) { 479 cfg.MaxPeers += lightPeers 480 } 481 } else { 482 if lightServer { 483 cfg.MaxPeers += lightPeers 484 } 485 if lightClient && ctx.GlobalIsSet(LightMaxPeersFlag.Name) && cfg.MaxPeers < lightPeers { 486 cfg.MaxPeers = lightPeers 487 } 488 } 489 if !(lightClient || lightServer) { 490 lightPeers = 0 491 } 492 ethPeers := cfg.MaxPeers - lightPeers 493 if lightClient { 494 ethPeers = 0 495 } 496 log.Info("Maximum peer count", "ETH", ethPeers, "LES", lightPeers, "total", cfg.MaxPeers) 497 498 if ctx.GlobalIsSet(MaxPendingPeersFlag.Name) { 499 cfg.MaxPendingPeers = ctx.GlobalInt(MaxPendingPeersFlag.Name) 500 } 501 if ctx.GlobalIsSet(NoDiscoverFlag.Name) || lightClient { 502 cfg.NoDiscovery = true 503 } 504 505 // if we're running a light client or server, force enable the v5 peer discovery 506 // unless it is explicitly disabled with --nodiscover note that explicitly specifying 507 // --v5disc overrides --nodiscover, in which case the later only disables v4 discovery 508 forceV5Discovery := (lightClient || lightServer) && !ctx.GlobalBool(NoDiscoverFlag.Name) 509 if ctx.GlobalIsSet(DiscoveryV5Flag.Name) { 510 cfg.DiscoveryV5 = ctx.GlobalBool(DiscoveryV5Flag.Name) 511 } else if forceV5Discovery { 512 cfg.DiscoveryV5 = true 513 } 514 515 if netrestrict := ctx.GlobalString(NetrestrictFlag.Name); netrestrict != "" { 516 list, err := netutil.ParseNetlist(netrestrict) 517 if err != nil { 518 Fatalf("Option %q: %v", NetrestrictFlag.Name, err) 519 } 520 cfg.NetRestrict = list 521 } 522 523 if ctx.GlobalBool(DeveloperFlag.Name) { 524 // --dev mode can't use p2p networking. 525 cfg.MaxPeers = 0 526 cfg.ListenAddr = ":0" 527 cfg.NoDiscovery = true 528 cfg.DiscoveryV5 = false 529 } 530 } 531 532 // SetNodeConfig applies node-related command line flags to the config. 533 func SetNodeConfig(ctx *cli.Context, cfg *node.Config) { 534 SetP2PConfig(ctx, &cfg.P2P) 535 setIPC(ctx, cfg) 536 setHTTP(ctx, cfg) 537 setGraphQL(ctx, cfg) 538 setWS(ctx, cfg) 539 setNodeUserIdent(ctx, cfg) 540 setDataDir(ctx, cfg) 541 setSmartCard(ctx, cfg) 542 if ctx.GlobalIsSet(RaftPortFlag.Name) { 543 cfg.RaftPort = ctx.GlobalInt(RaftPortFlag.Name) 544 } 545 if ctx.GlobalIsSet(MonitorModeFlag.Name) { 546 cfg.MonitorPort = ctx.GlobalInt(MonitorPortFlag.Name) 547 } 548 cfg.EnableNodePermission = ctx.GlobalBool(EnableNodePermissionFlag.Name) 549 cfg.TLSEnable = ctx.GlobalBool(PeerTLSEnabledFlag.Name) 550 cfg.APITLSEnable = ctx.GlobalBool(APITLSEnabledFlag.Name) 551 if ctx.GlobalIsSet(ExternalSignerFlag.Name) { 552 cfg.ExternalSigner = ctx.GlobalString(ExternalSignerFlag.Name) 553 } 554 555 if ctx.GlobalIsSet(KeyStoreDirFlag.Name) { 556 cfg.KeyStoreDir = ctx.GlobalString(KeyStoreDirFlag.Name) 557 } else { 558 cfg.KeyStoreDir, _ = filepath.Abs(filepath.Join(cfg.DataDir, KeyStoreDirFlag.Name)) 559 } 560 if ctx.GlobalIsSet(LightKDFFlag.Name) { 561 cfg.UseLightweightKDF = ctx.GlobalBool(LightKDFFlag.Name) 562 } 563 if ctx.GlobalIsSet(NoUSBFlag.Name) { 564 cfg.NoUSB = ctx.GlobalBool(NoUSBFlag.Name) 565 } 566 if ctx.GlobalIsSet(InsecureUnlockAllowedFlag.Name) { 567 cfg.InsecureUnlockAllowed = ctx.GlobalBool(InsecureUnlockAllowedFlag.Name) 568 } 569 if ctx.GlobalIsSet(PeerTLSDirFlag.Name) { 570 cfg.TLSDir = ctx.GlobalString(PeerTLSDirFlag.Name) 571 } 572 } 573 574 func setSmartCard(ctx *cli.Context, cfg *node.Config) { 575 // Skip enabling smartcards if no path is set 576 path := ctx.GlobalString(SmartCardDaemonPathFlag.Name) 577 if path == "" { 578 return 579 } 580 // Sanity check that the smartcard path is valid 581 fi, err := os.Stat(path) 582 if err != nil { 583 log.Debug("Smartcard socket not found, disabling", "err", err) 584 return 585 } 586 if fi.Mode()&os.ModeType != os.ModeSocket { 587 log.Error("Invalid smartcard daemon path", "path", path, "type", fi.Mode().String()) 588 return 589 } 590 // Smartcard daemon path exists and is a socket, enable it 591 cfg.SmartCardDaemonPath = path 592 } 593 594 func setDataDir(ctx *cli.Context, cfg *node.Config) { 595 switch { 596 case ctx.GlobalIsSet(DataDirFlag.Name): 597 cfg.DataDir = ctx.GlobalString(DataDirFlag.Name) 598 case ctx.GlobalBool(DeveloperFlag.Name): 599 cfg.DataDir = "" // unless explicitly requested, use memory databases 600 case ctx.GlobalBool(TestnetFlag.Name) && cfg.DataDir == node.DefaultDataDir(): 601 cfg.DataDir = filepath.Join(node.DefaultDataDir(), "testnet") 602 } 603 } 604 605 func setGPO(ctx *cli.Context, cfg *gasprice.Config) { 606 if ctx.GlobalIsSet(GpoBlocksFlag.Name) { 607 cfg.Blocks = ctx.GlobalInt(GpoBlocksFlag.Name) 608 } 609 if ctx.GlobalIsSet(GpoPercentileFlag.Name) { 610 cfg.Percentile = ctx.GlobalInt(GpoPercentileFlag.Name) 611 } 612 } 613 614 func setTxPool(ctx *cli.Context, cfg *core.TxPoolConfig) { 615 if ctx.GlobalIsSet(TxPoolLocalsFlag.Name) { 616 locals := strings.Split(ctx.GlobalString(TxPoolLocalsFlag.Name), ",") 617 for _, account := range locals { 618 if trimmed := strings.TrimSpace(account); !common.IsHexAddress(trimmed) { 619 Fatalf("Invalid account in --txpool.locals: %s", trimmed) 620 } else { 621 cfg.Locals = append(cfg.Locals, common.HexToAddress(account)) 622 } 623 } 624 } 625 if ctx.GlobalIsSet(TxPoolNoLocalsFlag.Name) { 626 cfg.NoLocals = ctx.GlobalBool(TxPoolNoLocalsFlag.Name) 627 } 628 if ctx.GlobalIsSet(TxPoolJournalFlag.Name) { 629 cfg.Journal = ctx.GlobalString(TxPoolJournalFlag.Name) 630 } 631 if ctx.GlobalIsSet(TxPoolRejournalFlag.Name) { 632 cfg.Rejournal = ctx.GlobalDuration(TxPoolRejournalFlag.Name) 633 } 634 if ctx.GlobalIsSet(TxPoolPriceLimitFlag.Name) { 635 cfg.PriceLimit = ctx.GlobalUint64(TxPoolPriceLimitFlag.Name) 636 } 637 if ctx.GlobalIsSet(TxPoolPriceBumpFlag.Name) { 638 cfg.PriceBump = ctx.GlobalUint64(TxPoolPriceBumpFlag.Name) 639 } 640 if ctx.GlobalIsSet(TxPoolAccountSlotsFlag.Name) { 641 cfg.AccountSlots = ctx.GlobalUint64(TxPoolAccountSlotsFlag.Name) 642 } 643 if ctx.GlobalIsSet(TxPoolGlobalSlotsFlag.Name) { 644 cfg.GlobalSlots = ctx.GlobalUint64(TxPoolGlobalSlotsFlag.Name) 645 } 646 if ctx.GlobalIsSet(TxPoolAccountQueueFlag.Name) { 647 cfg.AccountQueue = ctx.GlobalUint64(TxPoolAccountQueueFlag.Name) 648 } 649 if ctx.GlobalIsSet(TxPoolGlobalQueueFlag.Name) { 650 cfg.GlobalQueue = ctx.GlobalUint64(TxPoolGlobalQueueFlag.Name) 651 } 652 if ctx.GlobalIsSet(TxPoolLifetimeFlag.Name) { 653 cfg.Lifetime = ctx.GlobalDuration(TxPoolLifetimeFlag.Name) 654 } 655 } 656 657 func setEthash(ctx *cli.Context, cfg *eth.Config) { 658 if ctx.GlobalIsSet(EthashCacheDirFlag.Name) { 659 cfg.Ethash.CacheDir = ctx.GlobalString(EthashCacheDirFlag.Name) 660 } 661 if ctx.GlobalIsSet(EthashDatasetDirFlag.Name) { 662 cfg.Ethash.DatasetDir = ctx.GlobalString(EthashDatasetDirFlag.Name) 663 } 664 if ctx.GlobalIsSet(EthashCachesInMemoryFlag.Name) { 665 cfg.Ethash.CachesInMem = ctx.GlobalInt(EthashCachesInMemoryFlag.Name) 666 } 667 if ctx.GlobalIsSet(EthashCachesOnDiskFlag.Name) { 668 cfg.Ethash.CachesOnDisk = ctx.GlobalInt(EthashCachesOnDiskFlag.Name) 669 } 670 if ctx.GlobalIsSet(EthashDatasetsInMemoryFlag.Name) { 671 cfg.Ethash.DatasetsInMem = ctx.GlobalInt(EthashDatasetsInMemoryFlag.Name) 672 } 673 if ctx.GlobalIsSet(EthashDatasetsOnDiskFlag.Name) { 674 cfg.Ethash.DatasetsOnDisk = ctx.GlobalInt(EthashDatasetsOnDiskFlag.Name) 675 } 676 } 677 678 func setHotstuff(ctx *cli.Context, stack *node.Node, cfg *eth.Config) { 679 if ctx.GlobalBool(HotstuffModeFlag.Name) { 680 if !ctx.GlobalBool(MiningEnabledFlag.Name) { 681 return 682 } 683 id := uint32(ctx.GlobalUint(HotstuffIDFlag.Name)) 684 if id == 0 { 685 idpath := filepath.Join(stack.DataDir(), "hotstuff-id") 686 idbytes, err := os.ReadFile(idpath) 687 if err != nil { 688 Fatalf("read hotstuff secret key file failed:%s-%v", idpath, err) 689 } 690 id = binary.LittleEndian.Uint32(idbytes) 691 } 692 cfg.Hotstuff.Id.SetUint32(id) 693 694 secpath := ctx.GlobalString(HotstuffSecretFlag.Name) 695 if secpath == "" { 696 secpath = filepath.Join(stack.DataDir(), "hotstuff-sec") 697 } 698 699 secbytes, err := os.ReadFile(secpath) 700 if err != nil { 701 Fatalf("read hotstuff secret key file failed:%s-%v", secpath, err) 702 } 703 cfg.Hotstuff.Mine = true 704 cfg.Hotstuff.Key = new(bls.PrivateKey) 705 cfg.Hotstuff.Key.FromBytes(secbytes) 706 } 707 } 708 709 func setPbft(ctx *cli.Context, cfg *eth.Config) { 710 if ctx.GlobalIsSet(PbftRequestTimeoutFlag.Name) { 711 cfg.Pbft.RequestTimeout = ctx.GlobalUint64(PbftRequestTimeoutFlag.Name) 712 } 713 if ctx.GlobalIsSet(PbftBlockPeriodFlag.Name) { 714 cfg.Pbft.BlockPeriod = ctx.GlobalUint64(PbftBlockPeriodFlag.Name) 715 } 716 if ctx.GlobalIsSet(PbftEnableLightFlag.Name) { 717 cfg.Pbft.LightMode = ctx.GlobalBool(PbftEnableLightFlag.Name) 718 } 719 if ctx.GlobalIsSet(PbftMaxBlockTxsSealFlag.Name) { 720 pbft.MaxBlockTxs = ctx.GlobalUint64(PbftMaxBlockTxsSealFlag.Name) 721 } 722 } 723 724 func setMiner(ctx *cli.Context, cfg *miner.Config) { 725 if ctx.GlobalIsSet(MinerNotifyFlag.Name) { 726 cfg.Notify = strings.Split(ctx.GlobalString(MinerNotifyFlag.Name), ",") 727 } 728 if ctx.GlobalIsSet(MinerExtraDataFlag.Name) { 729 cfg.ExtraData = []byte(ctx.GlobalString(MinerExtraDataFlag.Name)) 730 } 731 if ctx.GlobalIsSet(MinerGasTargetFlag.Name) { 732 cfg.GasFloor = ctx.GlobalUint64(MinerGasTargetFlag.Name) 733 } 734 if ctx.GlobalIsSet(MinerGasLimitFlag.Name) { 735 cfg.GasCeil = ctx.GlobalUint64(MinerGasLimitFlag.Name) 736 } 737 if ctx.GlobalIsSet(MinerGasPriceFlag.Name) { 738 cfg.GasPrice = GlobalBig(ctx, MinerGasPriceFlag.Name) 739 } 740 if ctx.GlobalIsSet(MinerRecommitIntervalFlag.Name) { 741 cfg.Recommit = ctx.Duration(MinerRecommitIntervalFlag.Name) 742 } 743 if ctx.GlobalIsSet(MinerNoVerifyFlag.Name) { 744 cfg.Noverify = ctx.Bool(MinerNoVerifyFlag.Name) 745 } 746 cfg.NoEmptyBlock = ctx.GlobalIsSet(MinerNoEmptyBlockFlag.Name) 747 748 if ctx.GlobalIsSet(MinerTxLimitFlag.Name) { 749 cfg.TxLimit = ctx.GlobalInt(MinerTxLimitFlag.Name) 750 } 751 } 752 753 func setWhitelist(ctx *cli.Context, cfg *eth.Config) { 754 whitelist := ctx.GlobalString(WhitelistFlag.Name) 755 if whitelist == "" { 756 return 757 } 758 cfg.Whitelist = make(map[uint64]common.Hash) 759 for _, entry := range strings.Split(whitelist, ",") { 760 parts := strings.Split(entry, "=") 761 if len(parts) != 2 { 762 Fatalf("Invalid whitelist entry: %s", entry) 763 } 764 number, err := strconv.ParseUint(parts[0], 0, 64) 765 if err != nil { 766 Fatalf("Invalid whitelist block number %s: %v", parts[0], err) 767 } 768 var hash common.Hash 769 if err = hash.UnmarshalText([]byte(parts[1])); err != nil { 770 Fatalf("Invalid whitelist hash %s: %v", parts[1], err) 771 } 772 cfg.Whitelist[number] = hash 773 } 774 } 775 776 // CheckExclusive verifies that only a single instance of the provided flags was 777 // set by the user. Each flag might optionally be followed by a string type to 778 // specialize it further. 779 func CheckExclusive(ctx *cli.Context, args ...interface{}) { 780 set := make([]string, 0, 1) 781 for i := 0; i < len(args); i++ { 782 // Make sure the next argument is a flag and skip if not set 783 flag, ok := args[i].(cli.Flag) 784 if !ok { 785 panic(fmt.Sprintf("invalid argument, not cli.Flag type: %T", args[i])) 786 } 787 // Check if next arg extends current and expand its name if so 788 name := flag.GetName() 789 790 if i+1 < len(args) { 791 switch option := args[i+1].(type) { 792 case string: 793 // Extended flag check, make sure value set doesn't conflict with passed in option 794 if ctx.GlobalString(flag.GetName()) == option { 795 name += "=" + option 796 set = append(set, "--"+name) 797 } 798 // shift arguments and continue 799 i++ 800 continue 801 802 case cli.Flag: 803 default: 804 panic(fmt.Sprintf("invalid argument, not cli.Flag or string extension: %T", args[i+1])) 805 } 806 } 807 // Mark the flag if it's set 808 if ctx.GlobalIsSet(flag.GetName()) { 809 set = append(set, "--"+name) 810 } 811 } 812 if len(set) > 1 { 813 Fatalf("Flags %v can't be used at the same time", strings.Join(set, ", ")) 814 } 815 } 816 817 // SetShhConfig applies shh-related command line flags to the config. 818 func SetShhConfig(ctx *cli.Context, stack *node.Node, cfg *whisper.Config) { 819 if ctx.GlobalIsSet(WhisperMaxMessageSizeFlag.Name) { 820 cfg.MaxMessageSize = uint32(ctx.GlobalUint(WhisperMaxMessageSizeFlag.Name)) 821 } 822 if ctx.GlobalIsSet(WhisperMinPOWFlag.Name) { 823 cfg.MinimumAcceptedPOW = ctx.GlobalFloat64(WhisperMinPOWFlag.Name) 824 } 825 if ctx.GlobalIsSet(WhisperRestrictConnectionBetweenLightClientsFlag.Name) { 826 cfg.RestrictConnectionBetweenLightClients = true 827 } 828 } 829 830 // SetEthConfig applies eth-related command line flags to the config. 831 func SetEthConfig(ctx *cli.Context, stack *node.Node, cfg *eth.Config) { 832 // Avoid conflicting network flags 833 CheckExclusive(ctx, DeveloperFlag, TestnetFlag) 834 CheckExclusive(ctx, LightServeFlag, SyncModeFlag, "light") 835 CheckExclusive(ctx, DeveloperFlag, ExternalSignerFlag) // Can't use both ephemeral unlocked and external signer 836 837 var ks *keystore.KeyStore 838 if keystores := stack.AccountManager().Backends(keystore.KeyStoreType); len(keystores) > 0 { 839 ks = keystores[0].(*keystore.KeyStore) 840 } 841 setEtherbase(ctx, ks, cfg) 842 setGPO(ctx, &cfg.GPO) 843 setTxPool(ctx, &cfg.TxPool) 844 setEthash(ctx, cfg) 845 setHotstuff(ctx, stack, cfg) 846 setPbft(ctx, cfg) 847 setMiner(ctx, &cfg.Miner) 848 setWhitelist(ctx, cfg) 849 setLes(ctx, cfg) 850 851 if ctx.GlobalIsSet(SyncModeFlag.Name) { 852 cfg.SyncMode = *GlobalTextMarshaler(ctx, SyncModeFlag.Name).(*downloader.SyncMode) 853 } 854 if ctx.GlobalIsSet(NetworkIdFlag.Name) { 855 cfg.NetworkId = ctx.GlobalUint64(NetworkIdFlag.Name) 856 } 857 if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheDatabaseFlag.Name) { 858 cfg.DatabaseCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheDatabaseFlag.Name) / 100 859 } 860 cfg.DatabaseHandles = makeDatabaseHandles() 861 if ctx.GlobalIsSet(AncientFlag.Name) { 862 cfg.DatabaseFreezer = ctx.GlobalString(AncientFlag.Name) 863 } 864 865 if gcmode := ctx.GlobalString(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" { 866 Fatalf("--%s must be either 'full' or 'archive'", GCModeFlag.Name) 867 } 868 if ctx.GlobalIsSet(GCModeFlag.Name) { 869 cfg.NoPruning = ctx.GlobalString(GCModeFlag.Name) == "archive" 870 } 871 if ctx.GlobalIsSet(CacheNoPrefetchFlag.Name) { 872 cfg.NoPrefetch = ctx.GlobalBool(CacheNoPrefetchFlag.Name) 873 } 874 if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheTrieFlag.Name) { 875 cfg.TrieCleanCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheTrieFlag.Name) / 100 876 } 877 if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheGCFlag.Name) { 878 cfg.TrieDirtyCache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheGCFlag.Name) / 100 879 } 880 if ctx.GlobalIsSet(DocRootFlag.Name) { 881 cfg.DocRoot = ctx.GlobalString(DocRootFlag.Name) 882 } 883 if ctx.GlobalIsSet(VMEnableDebugFlag.Name) { 884 // TODO(fjl): force-enable this in --dev mode 885 cfg.EnablePreimageRecording = ctx.GlobalBool(VMEnableDebugFlag.Name) 886 } 887 888 if ctx.GlobalIsSet(EWASMInterpreterFlag.Name) { 889 cfg.EWASMInterpreter = ctx.GlobalString(EWASMInterpreterFlag.Name) 890 } 891 892 if ctx.GlobalIsSet(EVMInterpreterFlag.Name) { 893 cfg.EVMInterpreter = ctx.GlobalString(EVMInterpreterFlag.Name) 894 } 895 if ctx.GlobalIsSet(RPCGlobalGasCap.Name) { 896 cfg.RPCGasCap = new(big.Int).SetUint64(ctx.GlobalUint64(RPCGlobalGasCap.Name)) 897 } 898 899 // Override any default configs for hard coded networks. 900 switch { 901 case ctx.GlobalBool(TestnetFlag.Name): 902 if !ctx.GlobalIsSet(NetworkIdFlag.Name) { 903 cfg.NetworkId = 3 904 } 905 cfg.Genesis = core.DefaultTestnetGenesisBlock() 906 case ctx.GlobalBool(DeveloperFlag.Name): 907 if !ctx.GlobalIsSet(NetworkIdFlag.Name) { 908 cfg.NetworkId = 1337 909 } 910 // Create new developer account or reuse existing one 911 var ( 912 developer accounts.Account 913 err error 914 ) 915 if accs := ks.Accounts(); len(accs) > 0 { 916 developer = ks.Accounts()[0] 917 } else { 918 developer, err = ks.NewAccount("") 919 if err != nil { 920 Fatalf("Failed to create developer account: %v", err) 921 } 922 } 923 if err := ks.Unlock(developer, ""); err != nil { 924 Fatalf("Failed to unlock developer account: %v", err) 925 } 926 log.Info("Using developer account", "address", developer.Address) 927 928 cfg.Genesis = core.DeveloperGenesisBlock(uint64(ctx.GlobalInt(DeveloperPeriodFlag.Name)), developer.Address) 929 if !ctx.GlobalIsSet(MinerGasPriceFlag.Name) { 930 cfg.Miner.GasPrice = big.NewInt(1) 931 } 932 } 933 } 934 935 // RegisterEthService adds an SimpleService client to the stack. 936 func RegisterEthService(stack *node.Node, cfg *eth.Config) (<-chan *eth.SimpleService, <-chan *eth.SimpleService) { 937 nodeChan := make(chan *eth.SimpleService, 1) 938 raftChan := make(chan *eth.SimpleService, 1) 939 var err error 940 if cfg.SyncMode == downloader.LightSync { 941 err = stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { 942 return les.New(ctx, cfg) 943 }) 944 } else { 945 err = stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { 946 fullNode, err := eth.New(ctx, cfg) 947 if fullNode != nil && cfg.LightServ > 0 { 948 ls, _ := les.NewLesServer(fullNode, cfg) 949 fullNode.AddLesServer(ls) 950 } 951 nodeChan <- fullNode 952 raftChan <- fullNode 953 return fullNode, err 954 }) 955 } 956 if err != nil { 957 Fatalf("Failed to register the SimpleService service: %v", err) 958 } 959 return nodeChan, raftChan 960 } 961 962 // RegisterShhService configures Whisper and adds it to the given node. 963 func RegisterShhService(stack *node.Node, cfg *whisper.Config) { 964 if err := stack.Register(func(n *node.ServiceContext) (node.Service, error) { 965 return whisper.New(cfg), nil 966 }); err != nil { 967 Fatalf("Failed to register the Whisper service: %v", err) 968 } 969 } 970 971 // RegisterEthStatsService configures the SimpleService Stats daemon and adds it to 972 // the given node. 973 func RegisterEthStatsService(stack *node.Node, url string) { 974 if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { 975 // Retrieve both eth and les services 976 var ethServ *eth.SimpleService 977 ctx.Service(ðServ) 978 979 var lesServ *les.LightEthereum 980 ctx.Service(&lesServ) 981 982 // Let ethstats use whichever is not nil 983 return ethstats.New(url, ethServ, lesServ) 984 }); err != nil { 985 Fatalf("Failed to register the SimpleService Stats service: %v", err) 986 } 987 } 988 989 // RegisterGraphQLService is a utility function to construct a new service and register it against a node. 990 func RegisterGraphQLService(stack *node.Node, endpoint string, cors, vhosts []string, timeouts rpc.HTTPTimeouts) { 991 if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { 992 // Try to construct the GraphQL service backed by a full node 993 var ethServ *eth.SimpleService 994 if err := ctx.Service(ðServ); err == nil { 995 return graphql.New(ethServ.APIBackend, endpoint, cors, vhosts, timeouts) 996 } 997 // Try to construct the GraphQL service backed by a light node 998 var lesServ *les.LightEthereum 999 if err := ctx.Service(&lesServ); err == nil { 1000 return graphql.New(lesServ.ApiBackend, endpoint, cors, vhosts, timeouts) 1001 } 1002 // Well, this should not have happened, bail out 1003 return nil, errors.New("no SimpleService service") 1004 }); err != nil { 1005 Fatalf("Failed to register the GraphQL service: %v", err) 1006 } 1007 } 1008 1009 func SetupMetrics(ctx *cli.Context) { 1010 if metrics.Enabled { 1011 log.Info("Enabling metrics collection") 1012 var ( 1013 enableExport = ctx.GlobalBool(MetricsEnableInfluxDBFlag.Name) 1014 endpoint = ctx.GlobalString(MetricsInfluxDBEndpointFlag.Name) 1015 database = ctx.GlobalString(MetricsInfluxDBDatabaseFlag.Name) 1016 username = ctx.GlobalString(MetricsInfluxDBUsernameFlag.Name) 1017 password = ctx.GlobalString(MetricsInfluxDBPasswordFlag.Name) 1018 ) 1019 1020 if enableExport { 1021 tagsMap := SplitTagsFlag(ctx.GlobalString(MetricsInfluxDBTagsFlag.Name)) 1022 1023 log.Info("Enabling metrics export to InfluxDB") 1024 1025 go influxdb.InfluxDBWithTags(metrics.DefaultRegistry, 10*time.Second, endpoint, database, username, password, "geth.", tagsMap) 1026 } 1027 } 1028 } 1029 1030 func SplitTagsFlag(tagsFlag string) map[string]string { 1031 tags := strings.Split(tagsFlag, ",") 1032 tagsMap := map[string]string{} 1033 1034 for _, t := range tags { 1035 if t != "" { 1036 kv := strings.Split(t, "=") 1037 1038 if len(kv) == 2 { 1039 tagsMap[kv[0]] = kv[1] 1040 } 1041 } 1042 } 1043 1044 return tagsMap 1045 } 1046 1047 // MakeChainDatabase open an LevelDB using the flags passed to the client and will hard crash if it fails. 1048 func MakeChainDatabase(ctx *cli.Context, stack *node.Node) ethdb.Database { 1049 var ( 1050 cache = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheDatabaseFlag.Name) / 100 1051 handles = makeDatabaseHandles() 1052 ) 1053 name := "chaindata" 1054 if ctx.GlobalString(SyncModeFlag.Name) == "light" { 1055 name = "lightchaindata" 1056 } 1057 chainDb, err := stack.OpenDatabaseWithFreezer(name, cache, handles, ctx.GlobalString(AncientFlag.Name), "") 1058 if err != nil { 1059 Fatalf("Could not open database: %v", err) 1060 } 1061 return chainDb 1062 } 1063 1064 func MakeGenesis(ctx *cli.Context) *core.Genesis { 1065 var genesis *core.Genesis 1066 switch { 1067 case ctx.GlobalBool(TestnetFlag.Name): 1068 genesis = core.DefaultTestnetGenesisBlock() 1069 case ctx.GlobalBool(DeveloperFlag.Name): 1070 Fatalf("Developer chains are ephemeral") 1071 } 1072 return genesis 1073 } 1074 1075 // MakeChain creates a chain manager from set command line flags. 1076 func MakeChain(ctx *cli.Context, stack *node.Node) (chain *core.BlockChain, chainDb ethdb.Database) { 1077 var err error 1078 chainDb = MakeChainDatabase(ctx, stack) 1079 config, _, err := core.SetupGenesisBlock(chainDb, MakeGenesis(ctx)) 1080 if err != nil { 1081 Fatalf("%v", err) 1082 } 1083 var engine consensus.Engine 1084 if config.Clique != nil { 1085 engine = clique.New(config.Clique, chainDb) 1086 } else { 1087 engine = ethash.NewFaker() 1088 if !ctx.GlobalBool(FakePoWFlag.Name) { 1089 engine = ethash.New(ethash.Config{ 1090 CacheDir: stack.ResolvePath(eth.DefaultConfig.Ethash.CacheDir), 1091 CachesInMem: eth.DefaultConfig.Ethash.CachesInMem, 1092 CachesOnDisk: eth.DefaultConfig.Ethash.CachesOnDisk, 1093 DatasetDir: stack.ResolvePath(eth.DefaultConfig.Ethash.DatasetDir), 1094 DatasetsInMem: eth.DefaultConfig.Ethash.DatasetsInMem, 1095 DatasetsOnDisk: eth.DefaultConfig.Ethash.DatasetsOnDisk, 1096 }, nil, false) 1097 } 1098 } 1099 if gcmode := ctx.GlobalString(GCModeFlag.Name); gcmode != "full" && gcmode != "archive" { 1100 Fatalf("--%s must be either 'full' or 'archive'", GCModeFlag.Name) 1101 } 1102 cache := &core.CacheConfig{ 1103 TrieCleanLimit: eth.DefaultConfig.TrieCleanCache, 1104 TrieCleanNoPrefetch: ctx.GlobalBool(CacheNoPrefetchFlag.Name), 1105 TrieDirtyLimit: eth.DefaultConfig.TrieDirtyCache, 1106 TrieDirtyDisabled: ctx.GlobalString(GCModeFlag.Name) == "archive", 1107 TrieTimeLimit: eth.DefaultConfig.TrieTimeout, 1108 } 1109 if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheTrieFlag.Name) { 1110 cache.TrieCleanLimit = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheTrieFlag.Name) / 100 1111 } 1112 if ctx.GlobalIsSet(CacheFlag.Name) || ctx.GlobalIsSet(CacheGCFlag.Name) { 1113 cache.TrieDirtyLimit = ctx.GlobalInt(CacheFlag.Name) * ctx.GlobalInt(CacheGCFlag.Name) / 100 1114 } 1115 vmcfg := vm.Config{EnablePreimageRecording: ctx.GlobalBool(VMEnableDebugFlag.Name)} 1116 chain, err = core.NewBlockChain(chainDb, cache, config, engine, vmcfg, nil) 1117 if err != nil { 1118 Fatalf("Can't create BlockChain: %v", err) 1119 } 1120 return chain, chainDb 1121 } 1122 1123 // MakeConsolePreloads retrieves the absolute paths for the console JavaScript 1124 // scripts to preload before starting. 1125 func MakeConsolePreloads(ctx *cli.Context) []string { 1126 // Skip preloading if there's nothing to preload 1127 if ctx.GlobalString(PreloadJSFlag.Name) == "" { 1128 return nil 1129 } 1130 // Otherwise resolve absolute paths and return them 1131 var preloads []string 1132 1133 assets := ctx.GlobalString(JSpathFlag.Name) 1134 for _, file := range strings.Split(ctx.GlobalString(PreloadJSFlag.Name), ",") { 1135 preloads = append(preloads, common.AbsolutePath(assets, strings.TrimSpace(file))) 1136 } 1137 return preloads 1138 } 1139 1140 // MigrateFlags sets the global flag from a local flag when it's set. 1141 // This is a temporary function used for migrating old command/flags to the 1142 // new format. 1143 // 1144 // e.g. geth account new --keystore /tmp/mykeystore --lightkdf 1145 // 1146 // is equivalent after calling this method with: 1147 // 1148 // geth --keystore /tmp/mykeystore --lightkdf account new 1149 // 1150 // This allows the use of the existing configuration functionality. 1151 // When all flags are migrated this function can be removed and the existing 1152 // configuration functionality must be changed that is uses local flags 1153 func MigrateFlags(action func(ctx *cli.Context) error) func(*cli.Context) error { 1154 return func(ctx *cli.Context) error { 1155 for _, name := range ctx.FlagNames() { 1156 if ctx.IsSet(name) { 1157 ctx.GlobalSet(name, ctx.String(name)) 1158 } 1159 } 1160 return action(ctx) 1161 } 1162 } 1163 1164 // Configure smart-contract-based permissioning service 1165 func RegisterPermissionService(ctx *cli.Context, stack *node.Node, eth <-chan *eth.SimpleService) { 1166 if err := stack.Register(func(sctx *node.ServiceContext) (node.Service, error) { 1167 // start the permissions management service 1168 tmp1 := <-eth 1169 1170 pc, err := permission.NewPermissionService(stack, tmp1) 1171 if err != nil { 1172 return nil, fmt.Errorf("failed to load the permission contracts as given in %s due to %v", "params.PERMISSION_MODEL_CONFIG", err) 1173 } 1174 return pc, nil 1175 }); err != nil { 1176 Fatalf("Failed to register the permission service: %v", err) 1177 } 1178 log.Info("permission service registered") 1179 }