From 7225eec0f6a26228505a05521e126b7c03ad3c62 Mon Sep 17 00:00:00 2001 From: ferranbt <ferranbt@protonmail.com> Date: Sun, 17 Oct 2021 16:26:25 +0000 Subject: [PATCH] Finish flags --- .gitignore | 1 + command/flagset/flagset.go | 55 +++++------ command/flagset/flagset_test.go | 60 ++++++++++++ command/server/command.go | 95 +++++++++++++++++-- command/server/config.go | 162 ++++++++++++++++---------------- command/server/config_test.go | 90 ++++++++++++++++++ command/server/flags.go | 55 ++++++++--- go.mod | 1 + go.sum | 3 +- 9 files changed, 390 insertions(+), 132 deletions(-) create mode 100644 command/flagset/flagset_test.go create mode 100644 command/server/config_test.go diff --git a/.gitignore b/.gitignore index 1ee8b8302..15ccd00ed 100644 --- a/.gitignore +++ b/.gitignore @@ -47,3 +47,4 @@ profile.cov /dashboard/assets/package-lock.json **/yarn-error.log +./test diff --git a/command/flagset/flagset.go b/command/flagset/flagset.go index c272bfbca..c3c870499 100644 --- a/command/flagset/flagset.go +++ b/command/flagset/flagset.go @@ -78,10 +78,9 @@ func (f *Flagset) StringFlag(b *StringFlag) { } type IntFlag struct { - Name string - Usage string - Default int - Value *int + Name string + Usage string + Value *int } func (f *Flagset) IntFlag(i *IntFlag) { @@ -89,14 +88,13 @@ func (f *Flagset) IntFlag(i *IntFlag) { Name: i.Name, Usage: i.Usage, }) - f.set.IntVar(i.Value, i.Name, i.Default, i.Usage) + f.set.IntVar(i.Value, i.Name, *i.Value, i.Usage) } type Uint64Flag struct { - Name string - Usage string - Default uint64 - Value *uint64 + Name string + Usage string + Value *uint64 } func (f *Flagset) Uint64Flag(i *Uint64Flag) { @@ -104,17 +102,19 @@ func (f *Flagset) Uint64Flag(i *Uint64Flag) { Name: i.Name, Usage: i.Usage, }) - f.set.Uint64Var(i.Value, i.Name, i.Default, i.Usage) + f.set.Uint64Var(i.Value, i.Name, *i.Value, i.Usage) } type BigIntFlag struct { - Name string - Usage string - Default *big.Int - Value *big.Int + Name string + Usage string + Value *big.Int } func (b *BigIntFlag) String() string { + if b.Value == nil { + return "" + } return b.Value.String() } @@ -145,15 +145,18 @@ func (f *Flagset) BigIntFlag(b *BigIntFlag) { type SliceStringFlag struct { Name string Usage string - Value []string + Value *[]string } func (i *SliceStringFlag) String() string { - return strings.Join(i.Value, ",") + if i.Value == nil { + return "" + } + return strings.Join(*i.Value, ",") } func (i *SliceStringFlag) Set(value string) error { - i.Value = append(i.Value, value) + *i.Value = append(*i.Value, strings.Split(value, ",")...) return nil } @@ -171,25 +174,12 @@ type DurationFlag struct { Value *time.Duration } -func (d *DurationFlag) String() string { - return d.Value.String() -} - -func (d *DurationFlag) Set(value string) error { - v, err := time.ParseDuration(value) - if err != nil { - return err - } - d.Value = &v - return nil -} - func (f *Flagset) DurationFlag(d *DurationFlag) { f.addFlag(&FlagVar{ Name: d.Name, Usage: d.Usage, }) - f.set.Var(d, d.Name, d.Usage) + f.set.DurationVar(d.Value, d.Name, *d.Value, "") } type MapStringFlag struct { @@ -199,6 +189,9 @@ type MapStringFlag struct { } func (m *MapStringFlag) String() string { + if m.Value == nil { + return "" + } ls := []string{} for k, v := range *m.Value { ls = append(ls, k+"="+v) diff --git a/command/flagset/flagset_test.go b/command/flagset/flagset_test.go new file mode 100644 index 000000000..2f046c324 --- /dev/null +++ b/command/flagset/flagset_test.go @@ -0,0 +1,60 @@ +package flagset + +import ( + "testing" + "time" + + "github.com/stretchr/testify/assert" +) + +func TestFlagsetBool(t *testing.T) { + f := NewFlagSet("") + + value := false + f.BoolFlag(&BoolFlag{ + Name: "flag", + Value: &value, + }) + + assert.NoError(t, f.Parse([]string{"--flag", "true"})) + assert.Equal(t, value, true) +} + +func TestFlagsetSliceString(t *testing.T) { + f := NewFlagSet("") + + value := []string{} + f.SliceStringFlag(&SliceStringFlag{ + Name: "flag", + Value: &value, + }) + + assert.NoError(t, f.Parse([]string{"--flag", "a,b", "--flag", "c"})) + assert.Equal(t, value, []string{"a", "b", "c"}) +} + +func TestFlagsetDuration(t *testing.T) { + f := NewFlagSet("") + + value := time.Duration(0) + f.DurationFlag(&DurationFlag{ + Name: "flag", + Value: &value, + }) + + assert.NoError(t, f.Parse([]string{"--flag", "1m"})) + assert.Equal(t, value, 1*time.Minute) +} + +func TestFlagsetMapString(t *testing.T) { + f := NewFlagSet("") + + value := map[string]string{} + f.MapStringFlag(&MapStringFlag{ + Name: "flag", + Value: &value, + }) + + assert.NoError(t, f.Parse([]string{"--flag", "a=b,c=d"})) + assert.Equal(t, value, map[string]string{"a": "b", "c": "d"}) +} diff --git a/command/server/command.go b/command/server/command.go index 56b1e1f10..9e3df6a5f 100644 --- a/command/server/command.go +++ b/command/server/command.go @@ -3,13 +3,16 @@ package server import ( "fmt" "io" + "io/ioutil" "os" "os/signal" "strings" "syscall" "time" + "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts/keystore" + "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/eth/tracers" "github.com/ethereum/go-ethereum/ethstats" @@ -30,6 +33,9 @@ type Command struct { // cli configuration cliConfig *Config + // final configuration + config *Config + configFile string // bor node @@ -74,6 +80,7 @@ func (c *Command) Run(args []string) int { c.UI.Error(err.Error()) return 1 } + c.config = config // start the logger setupLogger(*config.LogLevel) @@ -121,7 +128,7 @@ func (c *Command) Run(args []string) int { } // register ethash service - if config.EthStats != nil { + if *config.EthStats != "" { if err := ethstats.New(stack, backend.APIBackend, backend.Engine(), *config.EthStats); err != nil { c.UI.Error(err.Error()) return 1 @@ -129,13 +136,23 @@ func (c *Command) Run(args []string) int { } // setup account manager (only keystore) + var borKeystore *keystore.KeyStore { keydir := stack.KeyStoreDir() n, p := keystore.StandardScryptN, keystore.StandardScryptP - if *config.UseLightweightKDF { + if *config.Accounts.UseLightweightKDF { n, p = keystore.LightScryptN, keystore.LightScryptP } - stack.AccountManager().AddBackend(keystore.NewKeyStore(keydir, n, p)) + borKeystore = keystore.NewKeyStore(keydir, n, p) + stack.AccountManager().AddBackend(borKeystore) + } + + // unlock accounts if necessary + if len(config.Accounts.Unlock) != 0 { + if err := c.unlockAccounts(borKeystore); err != nil { + c.UI.Error(fmt.Sprintf("failed to unlock: %v", err)) + return 1 + } } // sealing (if enabled) @@ -159,6 +176,49 @@ func (c *Command) Run(args []string) int { return c.handleSignals() } +func (c *Command) unlockAccounts(borKeystore *keystore.KeyStore) error { + // If insecure account unlocking is not allowed if node's APIs are exposed to external. + if !c.node.Config().InsecureUnlockAllowed && c.node.Config().ExtRPCEnabled() { + return fmt.Errorf("account unlock with HTTP access is forbidden") + } + + // read passwords from file if possible + passwords := []string{} + if *c.config.Accounts.PasswordFile != "" { + var err error + if passwords, err = readMultilineFile(*c.config.Accounts.PasswordFile); err != nil { + return err + } + } + decodePassword := func(addr common.Address, index int) (string, error) { + if len(passwords) > 0 { + if index < len(passwords) { + return passwords[index], nil + } + return passwords[len(passwords)-1], nil + } + // ask for the password + return c.UI.AskSecret(fmt.Sprintf("Please give a password to unlock '%s'", addr.String())) + } + + for index, addrStr := range c.config.Accounts.Unlock { + if !common.IsHexAddress(addrStr) { + return fmt.Errorf("unlock value '%s' is not an address", addrStr) + } + acct := accounts.Account{Address: common.HexToAddress(addrStr)} + + password, err := decodePassword(acct.Address, index) + if err != nil { + return err + } + if err := borKeystore.Unlock(acct, password); err != nil { + return err + } + log.Info("Unlocked account", "address", acct.Address.Hex()) + } + return nil +} + func (c *Command) setupMetrics(config *MetricsConfig) error { metrics.Enabled = *config.Enabled metrics.EnabledExpensive = *config.Expensive @@ -208,17 +268,19 @@ func (c *Command) handleSignals() int { gracefulCh := make(chan struct{}) go func() { c.node.Close() + c.node.Wait() close(gracefulCh) }() - select { - case <-signalCh: - return 1 - case <-time.After(5 * time.Second): - return 1 - case <-gracefulCh: - return 0 + for i := 10; i > 0; i-- { + select { + case <-signalCh: + log.Warn("Already shutting down, interrupt more force stop.", "times", i-1) + case <-gracefulCh: + return 0 + } } + return 1 } func setupLogger(logLevel string) { @@ -239,3 +301,16 @@ func setupLogger(logLevel string) { } log.Root().SetHandler(glogger) } + +func readMultilineFile(path string) ([]string, error) { + text, err := ioutil.ReadFile(path) + if err != nil { + return nil, err + } + lines := strings.Split(string(text), "\n") + // Sanitise DOS line endings. + for i := range lines { + lines[i] = strings.TrimRight(lines[i], "\r") + } + return lines, nil +} diff --git a/command/server/config.go b/command/server/config.go index 5236d20c7..20cfaa5cf 100644 --- a/command/server/config.go +++ b/command/server/config.go @@ -1,13 +1,13 @@ package server import ( - "crypto/ecdsa" "fmt" "io/ioutil" "math" "math/big" "os" "path/filepath" + "runtime" "strconv" "time" @@ -16,7 +16,6 @@ import ( "github.com/ethereum/go-ethereum/command/server/chains" "github.com/ethereum/go-ethereum/common" "github.com/ethereum/go-ethereum/common/fdlimit" - "github.com/ethereum/go-ethereum/crypto" "github.com/ethereum/go-ethereum/eth/downloader" "github.com/ethereum/go-ethereum/eth/ethconfig" "github.com/ethereum/go-ethereum/eth/gasprice" @@ -27,6 +26,7 @@ import ( "github.com/ethereum/go-ethereum/p2p/nat" "github.com/ethereum/go-ethereum/params" "github.com/imdario/mergo" + "github.com/mitchellh/go-homedir" gopsutil "github.com/shirou/gopsutil/mem" ) @@ -57,25 +57,25 @@ func durPtr(d time.Duration) *time.Duration { type Config struct { chain *chains.Chain - Chain *string - Debug *bool - Whitelist *map[string]string - UseLightweightKDF *bool - LogLevel *string - DataDir *string - P2P *P2PConfig - SyncMode *string - GcMode *string - Snapshot *bool - EthStats *string - Heimdall *HeimdallConfig - TxPool *TxPoolConfig - Sealer *SealerConfig - JsonRPC *JsonRPCConfig - Gpo *GpoConfig - Ethstats *string - Metrics *MetricsConfig - Cache *CacheConfig + Chain *string + Debug *bool + Whitelist *map[string]string + LogLevel *string + DataDir *string + P2P *P2PConfig + SyncMode *string + GcMode *string + Snapshot *bool + EthStats *string + Heimdall *HeimdallConfig + TxPool *TxPoolConfig + Sealer *SealerConfig + JsonRPC *JsonRPCConfig + Gpo *GpoConfig + Ethstats *string + Metrics *MetricsConfig + Cache *CacheConfig + Accounts *AccountsConfig } type P2PConfig struct { @@ -132,7 +132,6 @@ type JsonRPCConfig struct { Modules []string VHost []string Cors []string - Bind *string GasCap *uint64 TxFeeCap *float64 @@ -146,6 +145,7 @@ type APIConfig struct { Enabled *bool Port *uint64 Prefix *string + Host *string } type GpoConfig struct { @@ -187,14 +187,20 @@ type CacheConfig struct { TxLookupLimit *uint64 } +type AccountsConfig struct { + Unlock []string + PasswordFile *string + AllowInsecureUnlock *bool + UseLightweightKDF *bool +} + func DefaultConfig() *Config { return &Config{ - Chain: stringPtr("mainnet"), - Debug: boolPtr(false), - UseLightweightKDF: boolPtr(false), - Whitelist: mapStrPtr(map[string]string{}), - LogLevel: stringPtr("INFO"), - DataDir: stringPtr(node.DefaultDataDir()), + Chain: stringPtr("mainnet"), + Debug: boolPtr(false), + Whitelist: mapStrPtr(map[string]string{}), + LogLevel: stringPtr("INFO"), + DataDir: stringPtr(defaultDataDir()), P2P: &P2PConfig{ MaxPeers: uint64Ptr(30), MaxPendPeers: uint64Ptr(50), @@ -235,6 +241,7 @@ func DefaultConfig() *Config { }, Sealer: &SealerConfig{ Enabled: boolPtr(false), + Etherbase: stringPtr(""), GasCeil: uint64Ptr(8000000), GasPrice: big.NewInt(params.GWei), ExtraData: stringPtr(""), @@ -247,6 +254,7 @@ func DefaultConfig() *Config { }, JsonRPC: &JsonRPCConfig{ IPCDisable: boolPtr(false), + IPCPath: stringPtr(""), Modules: []string{"web3", "net"}, Cors: []string{"*"}, VHost: []string{"*"}, @@ -256,11 +264,13 @@ func DefaultConfig() *Config { Enabled: boolPtr(false), Port: uint64Ptr(8545), Prefix: stringPtr(""), + Host: stringPtr("localhost"), }, Ws: &APIConfig{ Enabled: boolPtr(false), Port: uint64Ptr(8546), Prefix: stringPtr(""), + Host: stringPtr("localhost"), }, Graphql: &APIConfig{ Enabled: boolPtr(false), @@ -295,6 +305,12 @@ func DefaultConfig() *Config { Preimages: boolPtr(false), TxLookupLimit: uint64Ptr(2350000), }, + Accounts: &AccountsConfig{ + Unlock: []string{}, + PasswordFile: stringPtr(""), + AllowInsecureUnlock: boolPtr(false), + UseLightweightKDF: boolPtr(false), + }, } } @@ -321,11 +337,6 @@ func (c *Config) loadChain() error { c.chain = chain // preload some default values that depend on the chain file - - // the genesis files defines default bootnodes - if c.P2P.Discovery.Bootnodes == nil { - c.P2P.Discovery.Bootnodes = c.chain.Bootnodes - } if c.P2P.Discovery.DNS == nil { c.P2P.Discovery.DNS = c.chain.DNS } @@ -368,11 +379,11 @@ func (c *Config) buildEth() (*ethconfig.Config, error) { n.Miner.GasCeil = *c.Sealer.GasCeil n.Miner.ExtraData = []byte(*c.Sealer.ExtraData) - if etherbase := c.Sealer.Etherbase; etherbase != nil { - if !common.IsHexAddress(*etherbase) { - return nil, fmt.Errorf("etherbase is not an address: %s", *etherbase) + if etherbase := *c.Sealer.Etherbase; etherbase != "" { + if !common.IsHexAddress(etherbase) { + return nil, fmt.Errorf("etherbase is not an address: %s", etherbase) } - n.Miner.Etherbase = common.HexToAddress(*etherbase) + n.Miner.Etherbase = common.HexToAddress(etherbase) } } @@ -495,17 +506,18 @@ func (c *Config) buildNode() (*node.Config, error) { ipcPath := "" if !*c.JsonRPC.IPCDisable { ipcPath = clientIdentifier + ".ipc" - if c.JsonRPC.IPCPath != nil { + if *c.JsonRPC.IPCPath != "" { ipcPath = *c.JsonRPC.IPCPath } } cfg := &node.Config{ - Name: clientIdentifier, - DataDir: *c.DataDir, - UseLightweightKDF: *c.UseLightweightKDF, - Version: params.VersionWithCommit(gitCommit, gitDate), - IPCPath: ipcPath, + Name: clientIdentifier, + DataDir: *c.DataDir, + UseLightweightKDF: *c.Accounts.UseLightweightKDF, + InsecureUnlockAllowed: *c.Accounts.AllowInsecureUnlock, + Version: params.VersionWithCommit(gitCommit, gitDate), + IPCPath: ipcPath, P2P: p2p.Config{ MaxPeers: int(*c.P2P.MaxPeers), MaxPendingPeers: int(*c.P2P.MaxPendPeers), @@ -526,11 +538,11 @@ func (c *Config) buildNode() (*node.Config, error) { // enable jsonrpc endpoints { if *c.JsonRPC.Http.Enabled { - cfg.HTTPHost = *c.JsonRPC.Bind + cfg.HTTPHost = *c.JsonRPC.Http.Host cfg.HTTPPort = int(*c.JsonRPC.Http.Port) } if *c.JsonRPC.Ws.Enabled { - cfg.WSHost = *c.JsonRPC.Bind + cfg.WSHost = *c.JsonRPC.Ws.Host cfg.WSPort = int(*c.JsonRPC.Ws.Port) } } @@ -541,15 +553,13 @@ func (c *Config) buildNode() (*node.Config, error) { } cfg.P2P.NAT = natif - // setup private key for DevP2P if not found - devP2PPrivKey, err := readDevP2PKey(*c.DataDir) - if err != nil { - return nil, err - } - cfg.P2P.PrivateKey = devP2PPrivKey - // Discovery - if cfg.P2P.BootstrapNodes, err = parseBootnodes(c.P2P.Discovery.Bootnodes); err != nil { + // if no bootnodes are defined, use the ones from the chain file. + bootnodes := c.P2P.Discovery.Bootnodes + if len(bootnodes) == 0 { + bootnodes = c.chain.Bootnodes + } + if cfg.P2P.BootstrapNodes, err = parseBootnodes(bootnodes); err != nil { return nil, err } if cfg.P2P.BootstrapNodesV5, err = parseBootnodes(c.P2P.Discovery.BootnodesV5); err != nil { @@ -572,8 +582,8 @@ func (c *Config) buildNode() (*node.Config, error) { func (c *Config) Merge(cc ...*Config) error { for _, elem := range cc { - if err := mergo.Merge(&c, elem); err != nil { - return err + if err := mergo.Merge(c, elem, mergo.WithOverride, mergo.WithAppendSlice); err != nil { + return fmt.Errorf("failed to merge configurations: %v", err) } } return nil @@ -605,30 +615,24 @@ func parseBootnodes(urls []string) ([]*enode.Node, error) { return dst, nil } -const devP2PKeyPath = "devp2p.key" - -func readDevP2PKey(dataDir string) (*ecdsa.PrivateKey, error) { - path := filepath.Join(dataDir, devP2PKeyPath) - _, err := os.Stat(path) - if err != nil && !os.IsNotExist(err) { - return nil, fmt.Errorf("failed to stat (%s): %v", path, err) - } - - if os.IsNotExist(err) { - priv, err := crypto.GenerateKey() - if err != nil { - return nil, err +func defaultDataDir() string { + // Try to place the data folder in the user's home dir + home, _ := homedir.Dir() + if home == "" { + // we cannot guess a stable location + return "" + } + switch runtime.GOOS { + case "darwin": + return filepath.Join(home, "Library", "Bor") + case "windows": + appdata := os.Getenv("LOCALAPPDATA") + if appdata == "" { + // Windows XP and below don't have LocalAppData. + panic("environment variable LocalAppData is undefined") } - if err := crypto.SaveECDSA(path, priv); err != nil { - return nil, err - } - return priv, nil - } - - // exists - priv, err := crypto.LoadECDSA(path) - if err != nil { - return nil, err + return filepath.Join(appdata, "Bor") + default: + return filepath.Join(home, ".bor") } - return priv, nil } diff --git a/command/server/config_test.go b/command/server/config_test.go new file mode 100644 index 000000000..386757a60 --- /dev/null +++ b/command/server/config_test.go @@ -0,0 +1,90 @@ +package server + +import ( + "testing" + + "github.com/stretchr/testify/assert" +) + +func TestConfigDefault(t *testing.T) { + // the default config should work out of the box + config := DefaultConfig() + assert.NoError(t, config.loadChain()) + + _, err := config.buildNode() + assert.NoError(t, err) + + _, err = config.buildEth() + assert.NoError(t, err) +} + +func TestConfigMerge(t *testing.T) { + c0 := &Config{ + Chain: stringPtr("0"), + Debug: boolPtr(false), + Whitelist: mapStrPtr(map[string]string{ + "a": "b", + }), + P2P: &P2PConfig{ + Discovery: &P2PDiscovery{ + StaticNodes: []string{ + "a", + }, + }, + }, + } + c1 := &Config{ + Chain: stringPtr("1"), + Whitelist: mapStrPtr(map[string]string{ + "b": "c", + }), + P2P: &P2PConfig{ + Discovery: &P2PDiscovery{ + StaticNodes: []string{ + "b", + }, + }, + }, + } + expected := &Config{ + Chain: stringPtr("1"), + Debug: boolPtr(false), + Whitelist: mapStrPtr(map[string]string{ + "a": "b", + "b": "c", + }), + P2P: &P2PConfig{ + Discovery: &P2PDiscovery{ + StaticNodes: []string{ + "a", + "b", + }, + }, + }, + } + assert.NoError(t, c0.Merge(c1)) + assert.Equal(t, c0, expected) +} + +var dummyEnodeAddr = "enode://0cb82b395094ee4a2915e9714894627de9ed8498fb881cec6db7c65e8b9a5bd7f2f25cc84e71e89d0947e51c76e85d0847de848c7782b13c0255247a6758178c@44.232.55.71:30303" + +func TestConfigBootnodesDefault(t *testing.T) { + t.Run("EmptyBootnodes", func(t *testing.T) { + // if no bootnodes are specific, we use the ones from the genesis chain + config := DefaultConfig() + assert.NoError(t, config.loadChain()) + + cfg, err := config.buildNode() + assert.NoError(t, err) + assert.NotEmpty(t, cfg.P2P.BootstrapNodes) + }) + t.Run("NotEmptyBootnodes", func(t *testing.T) { + // if bootnodes specific, DO NOT load the genesis bootnodes + config := DefaultConfig() + config.P2P.Discovery.Bootnodes = []string{dummyEnodeAddr} + + cfg, err := config.buildNode() + assert.NoError(t, err) + assert.Len(t, cfg.P2P.BootstrapNodes, 1) + }) +} diff --git a/command/server/flags.go b/command/server/flags.go index b0359d525..8513e1906 100644 --- a/command/server/flags.go +++ b/command/server/flags.go @@ -44,11 +44,6 @@ func (c *Command) Flags() *flagset.Flagset { Usage: `Blockchain garbage collection mode ("full", "archive")`, Value: c.cliConfig.GcMode, }) - f.BoolFlag(&flagset.BoolFlag{ - Name: "lightkdf", - Usage: "Reduce key-derivation RAM & CPU usage at some expense of KDF strength", - Value: c.cliConfig.UseLightweightKDF, - }) f.MapStringFlag(&flagset.MapStringFlag{ Name: "whitelist", Usage: "Comma separated block number-to-hash mappings to enforce (<number>=<hash>)", @@ -76,7 +71,7 @@ func (c *Command) Flags() *flagset.Flagset { f.SliceStringFlag(&flagset.SliceStringFlag{ Name: "txpool.locals", Usage: "Comma separated accounts to treat as locals (no flush, priority inclusion)", - Value: c.cliConfig.TxPool.Locals, + Value: &c.cliConfig.TxPool.Locals, }) f.BoolFlag(&flagset.BoolFlag{ Name: "txpool.nolocals", @@ -259,21 +254,32 @@ func (c *Command) Flags() *flagset.Flagset { Value: c.cliConfig.JsonRPC.IPCPath, }) f.SliceStringFlag(&flagset.SliceStringFlag{ - Name: "rpc.corsdomain", + Name: "jsonrpc.corsdomain", Usage: "Comma separated list of domains from which to accept cross origin requests (browser enforced)", - Value: c.cliConfig.JsonRPC.Cors, + Value: &c.cliConfig.JsonRPC.Cors, }) f.SliceStringFlag(&flagset.SliceStringFlag{ - Name: "rpc.vhosts", + Name: "jsonrpc.vhosts", Usage: "Comma separated list of virtual hostnames from which to accept requests (server enforced). Accepts '*' wildcard.", - Value: c.cliConfig.JsonRPC.VHost, + Value: &c.cliConfig.JsonRPC.VHost, + }) + f.SliceStringFlag(&flagset.SliceStringFlag{ + Name: "jsonrpc.modules", + Usage: "API's offered over the HTTP-RPC interface", + Value: &c.cliConfig.JsonRPC.Modules, }) + // http options f.BoolFlag(&flagset.BoolFlag{ Name: "http", Usage: "Enable the HTTP-RPC server", Value: c.cliConfig.JsonRPC.Http.Enabled, }) + f.StringFlag(&flagset.StringFlag{ + Name: "http.addr", + Usage: "HTTP-RPC server listening interface", + Value: c.cliConfig.JsonRPC.Http.Host, + }) f.Uint64Flag(&flagset.Uint64Flag{ Name: "http.port", Usage: "HTTP-RPC server listening port", @@ -290,6 +296,11 @@ func (c *Command) Flags() *flagset.Flagset { Usage: "Enable the WS-RPC server", Value: c.cliConfig.JsonRPC.Ws.Enabled, }) + f.StringFlag(&flagset.StringFlag{ + Name: "ws.addr", + Usage: "WS-RPC server listening interface", + Value: c.cliConfig.JsonRPC.Ws.Host, + }) f.Uint64Flag(&flagset.Uint64Flag{ Name: "ws.port", Usage: "WS-RPC server listening port", @@ -321,7 +332,7 @@ func (c *Command) Flags() *flagset.Flagset { f.SliceStringFlag(&flagset.SliceStringFlag{ Name: "bootnodes", Usage: "Comma separated enode URLs for P2P discovery bootstrap", - Value: c.cliConfig.P2P.Discovery.Bootnodes, + Value: &c.cliConfig.P2P.Discovery.Bootnodes, }) f.Uint64Flag(&flagset.Uint64Flag{ Name: "maxpeers", @@ -412,5 +423,27 @@ func (c *Command) Flags() *flagset.Flagset { Value: c.cliConfig.Metrics.InfluxDB.Organization, }) + // account + f.SliceStringFlag(&flagset.SliceStringFlag{ + Name: "unlock", + Usage: "Comma separated list of accounts to unlock", + Value: &c.cliConfig.Accounts.Unlock, + }) + f.StringFlag(&flagset.StringFlag{ + Name: "password", + Usage: "Password file to use for non-interactive password input", + Value: c.cliConfig.Accounts.PasswordFile, + }) + f.BoolFlag(&flagset.BoolFlag{ + Name: "allow-insecure-unlock", + Usage: "Allow insecure account unlocking when account-related RPCs are exposed by http", + Value: c.cliConfig.Accounts.AllowInsecureUnlock, + }) + f.BoolFlag(&flagset.BoolFlag{ + Name: "lightkdf", + Usage: "Reduce key-derivation RAM & CPU usage at some expense of KDF strength", + Value: c.cliConfig.Accounts.UseLightweightKDF, + }) + return f } diff --git a/go.mod b/go.mod index dfc33fc8c..b5f8b0032 100644 --- a/go.mod +++ b/go.mod @@ -51,6 +51,7 @@ require ( github.com/mattn/go-colorable v0.1.8 github.com/mattn/go-isatty v0.0.12 github.com/mitchellh/cli v1.1.2 + github.com/mitchellh/go-homedir v1.1.0 github.com/naoina/go-stringutil v0.1.0 // indirect github.com/naoina/toml v0.1.2-0.20170918210437-9fafd6967416 github.com/olekukonko/tablewriter v0.0.5 diff --git a/go.sum b/go.sum index 79bb6c6cf..a4b737eac 100644 --- a/go.sum +++ b/go.sum @@ -33,7 +33,6 @@ github.com/Azure/go-autorest/autorest/date v0.2.0 h1:yW+Zlqf26583pE43KhfnhFcdmSW github.com/Azure/go-autorest/autorest/date v0.2.0/go.mod h1:vcORJHLJEh643/Ioh9+vPmf1Ij9AEBM5FuBIXLmIy0g= github.com/Azure/go-autorest/autorest/mocks v0.1.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= github.com/Azure/go-autorest/autorest/mocks v0.2.0/go.mod h1:OTyCOPRA2IgIlWxVYxBee2F5Gr4kF2zd2J5cFRaIDN0= -github.com/Azure/go-autorest/autorest/mocks v0.3.0 h1:qJumjCaCudz+OcqE9/XtEPfvtOjOmKaui4EOpFI6zZc= github.com/Azure/go-autorest/autorest/mocks v0.3.0/go.mod h1:a8FDP3DYzQ4RYfVAxAN3SVSiiO77gL2j2ronKKP0syM= github.com/Azure/go-autorest/logger v0.1.0 h1:ruG4BSDXONFRrZZJ2GUXDiUyVpayPmb1GnWeHDdaNKY= github.com/Azure/go-autorest/logger v0.1.0/go.mod h1:oExouG+K6PryycPJfVSxi/koC6LSNgds39diKLz7Vrc= @@ -331,6 +330,8 @@ github.com/mitchellh/cli v1.1.2 h1:PvH+lL2B7IQ101xQL63Of8yFS2y+aDlsFcsqNc+u/Kw= github.com/mitchellh/cli v1.1.2/go.mod h1:6iaV0fGdElS6dPBx0EApTxHrcWvmJphyh2n8YBLPPZ4= github.com/mitchellh/copystructure v1.0.0 h1:Laisrj+bAB6b/yJwB5Bt3ITZhGJdqmxquMKeZ+mmkFQ= github.com/mitchellh/copystructure v1.0.0/go.mod h1:SNtv71yrdKgLRyLFxmLdkAbkKEFWgYaq1OVrnRcwhnw= +github.com/mitchellh/go-homedir v1.1.0 h1:lukF9ziXFxDFPkA1vsr5zpc1XuPDn/wFntq5mG+4E0Y= +github.com/mitchellh/go-homedir v1.1.0/go.mod h1:SfyaCUpYCn1Vlf4IUYiD9fPX4A5wJrkLzIz1N1q0pr0= github.com/mitchellh/reflectwalk v1.0.0 h1:9D+8oIskB4VJBN5SFlmc27fSlIBZaov1Wpk/IfikLNY= github.com/mitchellh/reflectwalk v1.0.0/go.mod h1:mSTlrgnPZtwu0c4WaC2kGObEpuNDbx0jmZXqmk4esnw= github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= -- GitLab