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(&ethServ)
   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(&ethServ); 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  }