diff --git a/docs/cli/server.md b/docs/cli/server.md index ba6f3389c5..f730d1b5f7 100644 --- a/docs/cli/server.md +++ b/docs/cli/server.md @@ -36,6 +36,8 @@ The ```bor server``` command runs the Bor client. - ```gpo.ignoreprice```: Gas price below which gpo will ignore transactions +- ```disable-bor-wallet```: Disable the personal wallet endpoints + - ```grpc.addr```: Address and port to bind the GRPC server - ```dev```: Enable developer mode with ephemeral proof-of-authority network and a pre-funded developer account, mining enabled diff --git a/eth/backend.go b/eth/backend.go index 05d6c5c927..f40e011f8d 100644 --- a/eth/backend.go +++ b/eth/backend.go @@ -82,6 +82,7 @@ type Ethereum struct { eventMux *event.TypeMux engine consensus.Engine accountManager *accounts.Manager + authorized bool // If consensus engine is authorized with keystore bloomRequests chan chan *bloombits.Retrieval // Channel receiving bloom data retrieval requests bloomIndexer *core.ChainIndexer // Bloom indexer operating during block imports @@ -153,6 +154,7 @@ func New(stack *node.Node, config *ethconfig.Config) (*Ethereum, error) { chainDb: chainDb, eventMux: stack.EventMux(), accountManager: stack.AccountManager(), + authorized: false, engine: nil, closeBloomHandler: make(chan struct{}), networkID: config.NetworkId, @@ -485,29 +487,34 @@ func (s *Ethereum) StartMining(threads int) error { log.Error("Cannot start mining without etherbase", "err", err) return fmt.Errorf("etherbase missing: %v", err) } - var cli *clique.Clique - if c, ok := s.engine.(*clique.Clique); ok { - cli = c - } else if cl, ok := s.engine.(*beacon.Beacon); ok { - if c, ok := cl.InnerEngine().(*clique.Clique); ok { + + // If personal endpoints are disabled, the server creating + // this Ethereum instance has already Authorized consensus. + if !s.authorized { + var cli *clique.Clique + if c, ok := s.engine.(*clique.Clique); ok { cli = c + } else if cl, ok := s.engine.(*beacon.Beacon); ok { + if c, ok := cl.InnerEngine().(*clique.Clique); ok { + cli = c + } } - } - if cli != nil { - wallet, err := s.accountManager.Find(accounts.Account{Address: eb}) - if wallet == nil || err != nil { - log.Error("Etherbase account unavailable locally", "err", err) - return fmt.Errorf("signer missing: %v", err) + if cli != nil { + wallet, err := s.accountManager.Find(accounts.Account{Address: eb}) + if wallet == nil || err != nil { + log.Error("Etherbase account unavailable locally", "err", err) + return fmt.Errorf("signer missing: %v", err) + } + cli.Authorize(eb, wallet.SignData) } - cli.Authorize(eb, wallet.SignData) - } - if bor, ok := s.engine.(*bor.Bor); ok { - wallet, err := s.accountManager.Find(accounts.Account{Address: eb}) - if wallet == nil || err != nil { - log.Error("Etherbase account unavailable locally", "err", err) - return fmt.Errorf("signer missing: %v", err) + if bor, ok := s.engine.(*bor.Bor); ok { + wallet, err := s.accountManager.Find(accounts.Account{Address: eb}) + if wallet == nil || err != nil { + log.Error("Etherbase account unavailable locally", "err", err) + return fmt.Errorf("signer missing: %v", err) + } + bor.Authorize(eb, wallet.SignData) } - bor.Authorize(eb, wallet.SignData) } // If mining is started, we can disable the transaction rejection mechanism // introduced to speed sync times. @@ -553,6 +560,14 @@ func (s *Ethereum) SyncMode() downloader.SyncMode { return mode } +// SetAuthorized sets the authorized bool variable +// denoting that consensus has been authorized while creation +func (s *Ethereum) SetAuthorized(authorized bool) { + s.lock.Lock() + s.authorized = authorized + s.lock.Unlock() +} + // Protocols returns all the currently configured // network protocols to start. func (s *Ethereum) Protocols() []p2p.Protocol { diff --git a/internal/cli/server/config.go b/internal/cli/server/config.go index a5e255ad48..67bae007b9 100644 --- a/internal/cli/server/config.go +++ b/internal/cli/server/config.go @@ -368,6 +368,9 @@ type AccountsConfig struct { // UseLightweightKDF enables a faster but less secure encryption of accounts UseLightweightKDF bool `hcl:"use-lightweight-kdf,optional"` + + // DisableBorWallet disables the personal wallet endpoints + DisableBorWallet bool `hcl:"disable-bor-wallet,optional"` } type DeveloperConfig struct { @@ -496,6 +499,7 @@ func DefaultConfig() *Config { PasswordFile: "", AllowInsecureUnlock: false, UseLightweightKDF: false, + DisableBorWallet: false, }, GRPC: &GRPCConfig{ Addr: ":3131", @@ -611,7 +615,7 @@ func (c *Config) loadChain() error { return nil } -func (c *Config) buildEth(stack *node.Node) (*ethconfig.Config, error) { +func (c *Config) buildEth(accountManager *accounts.Manager) (*ethconfig.Config, error) { dbHandles, err := makeDatabaseHandles() if err != nil { return nil, err @@ -667,7 +671,7 @@ func (c *Config) buildEth(stack *node.Node) (*ethconfig.Config, error) { if c.Developer.Enabled { // Get a keystore var ks *keystore.KeyStore - if keystores := stack.AccountManager().Backends(keystore.KeyStoreType); len(keystores) > 0 { + if keystores := accountManager.Backends(keystore.KeyStoreType); len(keystores) > 0 { ks = keystores[0].(*keystore.KeyStore) } @@ -693,6 +697,10 @@ func (c *Config) buildEth(stack *node.Node) (*ethconfig.Config, error) { } log.Info("Using developer account", "address", developer.Address) + // Set the Etherbase + c.Sealer.Etherbase = developer.Address.Hex() + n.Miner.Etherbase = developer.Address + // get developer mode chain config c.chain = chains.GetDeveloperChain(c.Developer.Period, developer.Address) diff --git a/internal/cli/server/flags.go b/internal/cli/server/flags.go index ce93e8c071..62bc534dac 100644 --- a/internal/cli/server/flags.go +++ b/internal/cli/server/flags.go @@ -530,6 +530,11 @@ func (c *Command) Flags() *flagset.Flagset { Value: &c.cliConfig.Accounts.UseLightweightKDF, Group: "Account Management", }) + f.BoolFlag((&flagset.BoolFlag{ + Name: "disable-bor-wallet", + Usage: "Disable the personal wallet endpoints", + Value: &c.cliConfig.Accounts.DisableBorWallet, + })) // grpc f.StringFlag(&flagset.StringFlag{ diff --git a/internal/cli/server/server.go b/internal/cli/server/server.go index 5d3d307d2a..6b4e7ed4da 100644 --- a/internal/cli/server/server.go +++ b/internal/cli/server/server.go @@ -10,7 +10,11 @@ import ( "strings" "time" + "github.com/ethereum/go-ethereum/accounts" "github.com/ethereum/go-ethereum/accounts/keystore" + "github.com/ethereum/go-ethereum/consensus/beacon" + "github.com/ethereum/go-ethereum/consensus/bor" + "github.com/ethereum/go-ethereum/consensus/clique" "github.com/ethereum/go-ethereum/eth" "github.com/ethereum/go-ethereum/eth/tracers" "github.com/ethereum/go-ethereum/ethstats" @@ -67,50 +71,115 @@ func NewServer(config *Config) (*Server, error) { if err != nil { return nil, err } - srv.node = stack // setup account manager (only keystore) - { - keydir := stack.KeyStoreDir() - n, p := keystore.StandardScryptN, keystore.StandardScryptP - if config.Accounts.UseLightweightKDF { - n, p = keystore.LightScryptN, keystore.LightScryptP - } - stack.AccountManager().AddBackend(keystore.NewKeyStore(keydir, n, p)) + // create a new account manager, only for the scope of this function + accountManager := accounts.NewManager(&accounts.Config{}) + + // register backend to account manager with keystore for signing + keydir := stack.KeyStoreDir() + n, p := keystore.StandardScryptN, keystore.StandardScryptP + if config.Accounts.UseLightweightKDF { + n, p = keystore.LightScryptN, keystore.LightScryptP } - // register the ethereum backend - ethCfg, err := config.buildEth(stack) - if err != nil { - return nil, err - } + // proceed to authorize the local account manager in any case + accountManager.AddBackend(keystore.NewKeyStore(keydir, n, p)) - backend, err := eth.New(stack, ethCfg) - if err != nil { - return nil, err + // flag to set if we're authorizing consensus here + authorized := false + + // check if personal wallet endpoints are disabled or not + if !config.Accounts.DisableBorWallet { + // add keystore globally to the node's account manager if personal wallet is enabled + stack.AccountManager().AddBackend(keystore.NewKeyStore(keydir, n, p)) + + // register the ethereum backend + ethCfg, err := config.buildEth(stack.AccountManager()) + if err != nil { + return nil, err + } + backend, err := eth.New(stack, ethCfg) + if err != nil { + return nil, err + } + srv.backend = backend + } else { + // register the ethereum backend (with temporary created account manager) + ethCfg, err := config.buildEth(accountManager) + if err != nil { + return nil, err + } + backend, err := eth.New(stack, ethCfg) + if err != nil { + return nil, err + } + srv.backend = backend + + // authorize only if mining or in developer mode + if config.Sealer.Enabled || config.Developer.Enabled { + // get the etherbase + eb, err := srv.backend.Etherbase() + if err != nil { + log.Error("Cannot start mining without etherbase", "err", err) + return nil, fmt.Errorf("etherbase missing: %v", err) + } + + // Authorize the clique consensus (if chosen) to sign using wallet signer + var cli *clique.Clique + if c, ok := srv.backend.Engine().(*clique.Clique); ok { + cli = c + } else if cl, ok := srv.backend.Engine().(*beacon.Beacon); ok { + if c, ok := cl.InnerEngine().(*clique.Clique); ok { + cli = c + } + } + if cli != nil { + wallet, err := accountManager.Find(accounts.Account{Address: eb}) + if wallet == nil || err != nil { + log.Error("Etherbase account unavailable locally", "err", err) + return nil, fmt.Errorf("signer missing: %v", err) + } + cli.Authorize(eb, wallet.SignData) + authorized = true + } + + // Authorize the bor consensus (if chosen) to sign using wallet signer + if bor, ok := srv.backend.Engine().(*bor.Bor); ok { + wallet, err := accountManager.Find(accounts.Account{Address: eb}) + if wallet == nil || err != nil { + log.Error("Etherbase account unavailable locally", "err", err) + return nil, fmt.Errorf("signer missing: %v", err) + } + bor.Authorize(eb, wallet.SignData) + authorized = true + } + } } - srv.backend = backend + + // set the auth status in backend + srv.backend.SetAuthorized(authorized) // debug tracing is enabled by default - stack.RegisterAPIs(tracers.APIs(backend.APIBackend)) + stack.RegisterAPIs(tracers.APIs(srv.backend.APIBackend)) // graphql is started from another place if config.JsonRPC.Graphql.Enabled { - if err := graphql.New(stack, backend.APIBackend, config.JsonRPC.Cors, config.JsonRPC.VHost); err != nil { + if err := graphql.New(stack, srv.backend.APIBackend, config.JsonRPC.Cors, config.JsonRPC.VHost); err != nil { return nil, fmt.Errorf("failed to register the GraphQL service: %v", err) } } // register ethash service if config.Ethstats != "" { - if err := ethstats.New(stack, backend.APIBackend, backend.Engine(), config.Ethstats); err != nil { + if err := ethstats.New(stack, srv.backend.APIBackend, srv.backend.Engine(), config.Ethstats); err != nil { return nil, err } } // sealing (if enabled) or in dev mode if config.Sealer.Enabled || config.Developer.Enabled { - if err := backend.StartMining(1); err != nil { + if err := srv.backend.StartMining(1); err != nil { return nil, err } } @@ -119,6 +188,9 @@ func NewServer(config *Config) (*Server, error) { return nil, err } + // Set the node instance + srv.node = stack + // start the node if err := srv.node.Start(); err != nil { return nil, err