aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFelix Lange <fjl@twurst.com>2016-08-16 00:38:32 +0800
committerFelix Lange <fjl@twurst.com>2016-08-17 23:39:03 +0800
commit312263c7d9457fe7c24aac8e42a4cf2efc6ccd8e (patch)
treee10f9cc260af1ce13cb67b02bbce9c17c3b09de2
parentd6625ac34dad741f5659ca1dad3b0179603d37f0 (diff)
downloadgo-tangerine-312263c7d9457fe7c24aac8e42a4cf2efc6ccd8e.tar.gz
go-tangerine-312263c7d9457fe7c24aac8e42a4cf2efc6ccd8e.tar.zst
go-tangerine-312263c7d9457fe7c24aac8e42a4cf2efc6ccd8e.zip
cmd/utils, node: create account manager in package node
The account manager was previously created by packge cmd/utils as part of flag processing and then passed down into eth.Ethereum through its config struct. Since we are starting to create nodes which do not have eth.Ethereum as a registered service, the code was rearranged to register the account manager as its own service. Making it a service is ugly though and it doesn't really fix the root cause: creating nodes without eth.Ethereum requires duplicating lots of code. This commit splits utils.MakeSystemNode into three functions, making creation of other node/service configurations easier. It also moves the account manager into Node so it can be used by those configurations without requiring package eth.
-rw-r--r--accounts/account_manager.go22
-rw-r--r--cmd/geth/accountcmd.go24
-rw-r--r--cmd/geth/consolecmd.go4
-rw-r--r--cmd/geth/main.go62
-rw-r--r--cmd/gethrpctest/main.go32
-rw-r--r--cmd/utils/flags.go135
-rw-r--r--console/console_test.go12
-rw-r--r--eth/backend.go11
-rw-r--r--node/config.go58
-rw-r--r--node/node.go34
-rw-r--r--node/service.go8
11 files changed, 207 insertions, 195 deletions
diff --git a/accounts/account_manager.go b/accounts/account_manager.go
index 982a2ca6e..bfb7556d6 100644
--- a/accounts/account_manager.go
+++ b/accounts/account_manager.go
@@ -34,8 +34,6 @@ import (
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
- "github.com/ethereum/go-ethereum/p2p"
- "github.com/ethereum/go-ethereum/rpc"
)
var (
@@ -342,23 +340,3 @@ func zeroKey(k *ecdsa.PrivateKey) {
b[i] = 0
}
}
-
-// APIs implements node.Service
-func (am *Manager) APIs() []rpc.API {
- return nil
-}
-
-// Protocols implements node.Service
-func (am *Manager) Protocols() []p2p.Protocol {
- return nil
-}
-
-// Start implements node.Service
-func (am *Manager) Start(srvr *p2p.Server) error {
- return nil
-}
-
-// Stop implements node.Service
-func (am *Manager) Stop() error {
- return nil
-}
diff --git a/cmd/geth/accountcmd.go b/cmd/geth/accountcmd.go
index 7fea16a25..2069df6cd 100644
--- a/cmd/geth/accountcmd.go
+++ b/cmd/geth/accountcmd.go
@@ -168,8 +168,8 @@ nodes.
)
func accountList(ctx *cli.Context) error {
- accman := utils.MakeAccountManager(ctx)
- for i, acct := range accman.Accounts() {
+ stack := utils.MakeNode(ctx, clientIdentifier, verString)
+ for i, acct := range stack.AccountManager().Accounts() {
fmt.Printf("Account #%d: {%x} %s\n", i, acct.Address, acct.File)
}
return nil
@@ -261,10 +261,10 @@ func ambiguousAddrRecovery(am *accounts.Manager, err *accounts.AmbiguousAddrErro
// accountCreate creates a new account into the keystore defined by the CLI flags.
func accountCreate(ctx *cli.Context) error {
- accman := utils.MakeAccountManager(ctx)
+ stack := utils.MakeNode(ctx, clientIdentifier, verString)
password := getPassPhrase("Your new account is locked with a password. Please give a password. Do not forget this password.", true, 0, utils.MakePasswordList(ctx))
- account, err := accman.NewAccount(password)
+ account, err := stack.AccountManager().NewAccount(password)
if err != nil {
utils.Fatalf("Failed to create account: %v", err)
}
@@ -278,11 +278,10 @@ func accountUpdate(ctx *cli.Context) error {
if len(ctx.Args()) == 0 {
utils.Fatalf("No accounts specified to update")
}
- accman := utils.MakeAccountManager(ctx)
-
- account, oldPassword := unlockAccount(ctx, accman, ctx.Args().First(), 0, nil)
+ stack := utils.MakeNode(ctx, clientIdentifier, verString)
+ account, oldPassword := unlockAccount(ctx, stack.AccountManager(), ctx.Args().First(), 0, nil)
newPassword := getPassPhrase("Please give a new password. Do not forget this password.", true, 0, nil)
- if err := accman.Update(account, oldPassword, newPassword); err != nil {
+ if err := stack.AccountManager().Update(account, oldPassword, newPassword); err != nil {
utils.Fatalf("Could not update the account: %v", err)
}
return nil
@@ -298,10 +297,9 @@ func importWallet(ctx *cli.Context) error {
utils.Fatalf("Could not read wallet file: %v", err)
}
- accman := utils.MakeAccountManager(ctx)
+ stack := utils.MakeNode(ctx, clientIdentifier, verString)
passphrase := getPassPhrase("", false, 0, utils.MakePasswordList(ctx))
-
- acct, err := accman.ImportPreSaleKey(keyJson, passphrase)
+ acct, err := stack.AccountManager().ImportPreSaleKey(keyJson, passphrase)
if err != nil {
utils.Fatalf("%v", err)
}
@@ -318,9 +316,9 @@ func accountImport(ctx *cli.Context) error {
if err != nil {
utils.Fatalf("Failed to load the private key: %v", err)
}
- accman := utils.MakeAccountManager(ctx)
+ stack := utils.MakeNode(ctx, clientIdentifier, verString)
passphrase := getPassPhrase("Your new account is locked with a password. Please give a password. Do not forget this password.", true, 0, utils.MakePasswordList(ctx))
- acct, err := accman.ImportECDSA(key, passphrase)
+ acct, err := stack.AccountManager().ImportECDSA(key, passphrase)
if err != nil {
utils.Fatalf("Could not create the account: %v", err)
}
diff --git a/cmd/geth/consolecmd.go b/cmd/geth/consolecmd.go
index 8d53809ce..92d6f7f86 100644
--- a/cmd/geth/consolecmd.go
+++ b/cmd/geth/consolecmd.go
@@ -65,7 +65,7 @@ JavaScript API. See https://github.com/ethereum/go-ethereum/wiki/Javascipt-Conso
// same time.
func localConsole(ctx *cli.Context) error {
// Create and start the node based on the CLI flags
- node := utils.MakeSystemNode(clientIdentifier, verString, relConfig, makeDefaultExtra(), ctx)
+ node := makeFullNode(ctx)
startNode(ctx, node)
defer node.Stop()
@@ -149,7 +149,7 @@ func dialRPC(endpoint string) (*rpc.Client, error) {
// everything down.
func ephemeralConsole(ctx *cli.Context) error {
// Create and start the node based on the CLI flags
- node := utils.MakeSystemNode(clientIdentifier, verString, relConfig, makeDefaultExtra(), ctx)
+ node := makeFullNode(ctx)
startNode(ctx, node)
defer node.Stop()
diff --git a/cmd/geth/main.go b/cmd/geth/main.go
index 5f1157b90..de679ccca 100644
--- a/cmd/geth/main.go
+++ b/cmd/geth/main.go
@@ -29,7 +29,6 @@ import (
"time"
"github.com/ethereum/ethash"
- "github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/cmd/utils"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/console"
@@ -244,34 +243,13 @@ func main() {
}
}
-func makeDefaultExtra() []byte {
- var clientInfo = struct {
- Version uint
- Name string
- GoVersion string
- Os string
- }{uint(versionMajor<<16 | versionMinor<<8 | versionPatch), clientIdentifier, runtime.Version(), runtime.GOOS}
- extra, err := rlp.EncodeToBytes(clientInfo)
- if err != nil {
- glog.V(logger.Warn).Infoln("error setting canonical miner information:", err)
- }
-
- if uint64(len(extra)) > params.MaximumExtraDataSize.Uint64() {
- glog.V(logger.Warn).Infoln("error setting canonical miner information: extra exceeds", params.MaximumExtraDataSize)
- glog.V(logger.Debug).Infof("extra: %x\n", extra)
- return nil
- }
- return extra
-}
-
// geth is the main entry point into the system if no special subcommand is ran.
// It creates a default node based on the command line arguments and runs it in
// blocking mode, waiting for it to be shut down.
func geth(ctx *cli.Context) error {
- node := utils.MakeSystemNode(clientIdentifier, verString, relConfig, makeDefaultExtra(), ctx)
+ node := makeFullNode(ctx)
startNode(ctx, node)
node.Wait()
-
return nil
}
@@ -301,6 +279,38 @@ func initGenesis(ctx *cli.Context) error {
return nil
}
+func makeFullNode(ctx *cli.Context) *node.Node {
+ node := utils.MakeNode(ctx, clientIdentifier, verString)
+ utils.RegisterEthService(ctx, node, relConfig, makeDefaultExtra())
+ // Whisper must be explicitly enabled, but is auto-enabled in --dev mode.
+ shhEnabled := ctx.GlobalBool(utils.WhisperEnabledFlag.Name)
+ shhAutoEnabled := !ctx.GlobalIsSet(utils.WhisperEnabledFlag.Name) && ctx.GlobalIsSet(utils.DevModeFlag.Name)
+ if shhEnabled || shhAutoEnabled {
+ utils.RegisterShhService(node)
+ }
+ return node
+}
+
+func makeDefaultExtra() []byte {
+ var clientInfo = struct {
+ Version uint
+ Name string
+ GoVersion string
+ Os string
+ }{uint(versionMajor<<16 | versionMinor<<8 | versionPatch), clientIdentifier, runtime.Version(), runtime.GOOS}
+ extra, err := rlp.EncodeToBytes(clientInfo)
+ if err != nil {
+ glog.V(logger.Warn).Infoln("error setting canonical miner information:", err)
+ }
+
+ if uint64(len(extra)) > params.MaximumExtraDataSize.Uint64() {
+ glog.V(logger.Warn).Infoln("error setting canonical miner information: extra exceeds", params.MaximumExtraDataSize)
+ glog.V(logger.Debug).Infof("extra: %x\n", extra)
+ return nil
+ }
+ return extra
+}
+
// startNode boots up the system node and all registered protocols, after which
// it unlocks any requested accounts, and starts the RPC/IPC interfaces and the
// miner.
@@ -311,12 +321,8 @@ func startNode(ctx *cli.Context, stack *node.Node) {
utils.StartNode(stack)
// Unlock any account specifically requested
- var accman *accounts.Manager
- if err := stack.Service(&accman); err != nil {
- utils.Fatalf("ethereum service not running: %v", err)
- }
+ accman := stack.AccountManager()
passwords := utils.MakePasswordList(ctx)
-
accounts := strings.Split(ctx.GlobalString(utils.UnlockedAccountFlag.Name), ",")
for i, account := range accounts {
if trimmed := strings.TrimSpace(account); trimmed != "" {
diff --git a/cmd/gethrpctest/main.go b/cmd/gethrpctest/main.go
index 2e07e9426..d267dbf58 100644
--- a/cmd/gethrpctest/main.go
+++ b/cmd/gethrpctest/main.go
@@ -19,12 +19,10 @@ package main
import (
"flag"
- "io/ioutil"
"log"
"os"
"os/signal"
- "github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/crypto"
@@ -61,14 +59,8 @@ func main() {
if !found {
log.Fatalf("Requested test (%s) not found within suite", *testName)
}
- // Create the protocol stack to run the test with
- keydir, err := ioutil.TempDir("", "")
- if err != nil {
- log.Fatalf("Failed to create temporary keystore directory: %v", err)
- }
- defer os.RemoveAll(keydir)
- stack, err := MakeSystemNode(keydir, *testKey, test)
+ stack, err := MakeSystemNode(*testKey, test)
if err != nil {
log.Fatalf("Failed to assemble test stack: %v", err)
}
@@ -92,23 +84,24 @@ func main() {
// MakeSystemNode configures a protocol stack for the RPC tests based on a given
// keystore path and initial pre-state.
-func MakeSystemNode(keydir string, privkey string, test *tests.BlockTest) (*node.Node, error) {
+func MakeSystemNode(privkey string, test *tests.BlockTest) (*node.Node, error) {
// Create a networkless protocol stack
stack, err := node.New(&node.Config{
- IPCPath: node.DefaultIPCEndpoint(),
- HTTPHost: common.DefaultHTTPHost,
- HTTPPort: common.DefaultHTTPPort,
- HTTPModules: []string{"admin", "db", "eth", "debug", "miner", "net", "shh", "txpool", "personal", "web3"},
- WSHost: common.DefaultWSHost,
- WSPort: common.DefaultWSPort,
- WSModules: []string{"admin", "db", "eth", "debug", "miner", "net", "shh", "txpool", "personal", "web3"},
- NoDiscovery: true,
+ UseLightweightKDF: true,
+ IPCPath: node.DefaultIPCEndpoint(),
+ HTTPHost: common.DefaultHTTPHost,
+ HTTPPort: common.DefaultHTTPPort,
+ HTTPModules: []string{"admin", "db", "eth", "debug", "miner", "net", "shh", "txpool", "personal", "web3"},
+ WSHost: common.DefaultWSHost,
+ WSPort: common.DefaultWSPort,
+ WSModules: []string{"admin", "db", "eth", "debug", "miner", "net", "shh", "txpool", "personal", "web3"},
+ NoDiscovery: true,
})
if err != nil {
return nil, err
}
// Create the keystore and inject an unlocked account if requested
- accman := accounts.NewPlaintextManager(keydir)
+ accman := stack.AccountManager()
if len(privkey) > 0 {
key, err := crypto.HexToECDSA(privkey)
if err != nil {
@@ -131,7 +124,6 @@ func MakeSystemNode(keydir string, privkey string, test *tests.BlockTest) (*node
TestGenesisState: db,
TestGenesisBlock: test.Genesis,
ChainConfig: &core.ChainConfig{HomesteadBlock: params.MainNetHomesteadBlock},
- AccountManager: accman,
}
if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) { return eth.New(ctx, ethConf) }); err != nil {
return nil, err
diff --git a/cmd/utils/flags.go b/cmd/utils/flags.go
index de379f84f..067faf3ce 100644
--- a/cmd/utils/flags.go
+++ b/cmd/utils/flags.go
@@ -413,16 +413,6 @@ func MustMakeDataDir(ctx *cli.Context) string {
return ""
}
-// MakeKeyStoreDir resolves the folder to use for storing the account keys from the
-// set command line flags, returning the explicitly requested path, or one inside
-// the data directory otherwise.
-func MakeKeyStoreDir(datadir string, ctx *cli.Context) string {
- if path := ctx.GlobalString(KeyStoreDirFlag.Name); path != "" {
- return path
- }
- return filepath.Join(datadir, "keystore")
-}
-
// MakeIPCPath creates an IPC path configuration from the set command line flags,
// returning an empty string if IPC was explicitly disabled, or the set path.
func MakeIPCPath(ctx *cli.Context) string {
@@ -555,20 +545,6 @@ func MakeDatabaseHandles() int {
return limit / 2 // Leave half for networking and other stuff
}
-// MakeAccountManager creates an account manager from set command line flags.
-func MakeAccountManager(ctx *cli.Context) *accounts.Manager {
- // Create the keystore crypto primitive, light if requested
- scryptN := accounts.StandardScryptN
- scryptP := accounts.StandardScryptP
- if ctx.GlobalBool(LightKDFFlag.Name) {
- scryptN = accounts.LightScryptN
- scryptP = accounts.LightScryptP
- }
- datadir := MustMakeDataDir(ctx)
- keydir := MakeKeyStoreDir(datadir, ctx)
- return accounts.NewManager(keydir, scryptN, scryptP)
-}
-
// MakeAddress converts an account specified directly as a hex encoded string or
// a key index in the key store to an internal account representation.
func MakeAddress(accman *accounts.Manager, account string) (accounts.Account, error) {
@@ -631,9 +607,48 @@ func MakePasswordList(ctx *cli.Context) []string {
return lines
}
-// MakeSystemNode sets up a local node, configures the services to launch and
-// assembles the P2P protocol stack.
-func MakeSystemNode(name, version string, relconf release.Config, extra []byte, ctx *cli.Context) *node.Node {
+// MakeNode configures a node with no services from command line flags.
+func MakeNode(ctx *cli.Context, name, version string) *node.Node {
+ config := &node.Config{
+ DataDir: MustMakeDataDir(ctx),
+ KeyStoreDir: ctx.GlobalString(KeyStoreDirFlag.Name),
+ UseLightweightKDF: ctx.GlobalBool(LightKDFFlag.Name),
+ PrivateKey: MakeNodeKey(ctx),
+ Name: MakeNodeName(name, version, ctx),
+ NoDiscovery: ctx.GlobalBool(NoDiscoverFlag.Name),
+ BootstrapNodes: MakeBootstrapNodes(ctx),
+ ListenAddr: MakeListenAddress(ctx),
+ NAT: MakeNAT(ctx),
+ MaxPeers: ctx.GlobalInt(MaxPeersFlag.Name),
+ MaxPendingPeers: ctx.GlobalInt(MaxPendingPeersFlag.Name),
+ IPCPath: MakeIPCPath(ctx),
+ HTTPHost: MakeHTTPRpcHost(ctx),
+ HTTPPort: ctx.GlobalInt(RPCPortFlag.Name),
+ HTTPCors: ctx.GlobalString(RPCCORSDomainFlag.Name),
+ HTTPModules: MakeRPCModules(ctx.GlobalString(RPCApiFlag.Name)),
+ WSHost: MakeWSRpcHost(ctx),
+ WSPort: ctx.GlobalInt(WSPortFlag.Name),
+ WSOrigins: ctx.GlobalString(WSAllowedOriginsFlag.Name),
+ WSModules: MakeRPCModules(ctx.GlobalString(WSApiFlag.Name)),
+ }
+ if ctx.GlobalBool(DevModeFlag.Name) {
+ if !ctx.GlobalIsSet(DataDirFlag.Name) {
+ config.DataDir = filepath.Join(os.TempDir(), "/ethereum_dev_mode")
+ }
+ // --dev mode does not need p2p networking.
+ config.MaxPeers = 0
+ config.ListenAddr = ":0"
+ }
+ stack, err := node.New(config)
+ if err != nil {
+ Fatalf("Failed to create the protocol stack: %v", err)
+ }
+ return stack
+}
+
+// RegisterEthService configures eth.Ethereum from command line flags and adds it to the
+// given node.
+func RegisterEthService(ctx *cli.Context, stack *node.Node, relconf release.Config, extra []byte) {
// Avoid conflicting network flags
networks, netFlags := 0, []cli.BoolFlag{DevModeFlag, TestNetFlag, OlympicFlag}
for _, flag := range netFlags {
@@ -644,29 +659,6 @@ func MakeSystemNode(name, version string, relconf release.Config, extra []byte,
if networks > 1 {
Fatalf("The %v flags are mutually exclusive", netFlags)
}
- // Configure the node's service container
- stackConf := &node.Config{
- DataDir: MustMakeDataDir(ctx),
- PrivateKey: MakeNodeKey(ctx),
- Name: MakeNodeName(name, version, ctx),
- NoDiscovery: ctx.GlobalBool(NoDiscoverFlag.Name),
- BootstrapNodes: MakeBootstrapNodes(ctx),
- ListenAddr: MakeListenAddress(ctx),
- NAT: MakeNAT(ctx),
- MaxPeers: ctx.GlobalInt(MaxPeersFlag.Name),
- MaxPendingPeers: ctx.GlobalInt(MaxPendingPeersFlag.Name),
- IPCPath: MakeIPCPath(ctx),
- HTTPHost: MakeHTTPRpcHost(ctx),
- HTTPPort: ctx.GlobalInt(RPCPortFlag.Name),
- HTTPCors: ctx.GlobalString(RPCCORSDomainFlag.Name),
- HTTPModules: MakeRPCModules(ctx.GlobalString(RPCApiFlag.Name)),
- WSHost: MakeWSRpcHost(ctx),
- WSPort: ctx.GlobalInt(WSPortFlag.Name),
- WSOrigins: ctx.GlobalString(WSAllowedOriginsFlag.Name),
- WSModules: MakeRPCModules(ctx.GlobalString(WSApiFlag.Name)),
- }
- // Configure the Ethereum service
- accman := MakeAccountManager(ctx)
// initialise new random number generator
rand := rand.New(rand.NewSource(time.Now().UnixNano()))
@@ -679,14 +671,13 @@ func MakeSystemNode(name, version string, relconf release.Config, extra []byte,
}
ethConf := &eth.Config{
+ Etherbase: MakeEtherbase(stack.AccountManager(), ctx),
ChainConfig: MustMakeChainConfig(ctx),
FastSync: ctx.GlobalBool(FastSyncFlag.Name),
BlockChainVersion: ctx.GlobalInt(BlockchainVersionFlag.Name),
DatabaseCache: ctx.GlobalInt(CacheFlag.Name),
DatabaseHandles: MakeDatabaseHandles(),
NetworkId: ctx.GlobalInt(NetworkIdFlag.Name),
- AccountManager: accman,
- Etherbase: MakeEtherbase(accman, ctx),
MinerThreads: ctx.GlobalInt(MinerThreadsFlag.Name),
ExtraData: MakeMinerExtra(extra, ctx),
NatSpec: ctx.GlobalBool(NatspecEnabledFlag.Name),
@@ -703,8 +694,6 @@ func MakeSystemNode(name, version string, relconf release.Config, extra []byte,
SolcPath: ctx.GlobalString(SolcPathFlag.Name),
AutoDAG: ctx.GlobalBool(AutoDAGFlag.Name) || ctx.GlobalBool(MiningEnabledFlag.Name),
}
- // Configure the Whisper service
- shhEnable := ctx.GlobalBool(WhisperEnabledFlag.Name)
// Override any default configs in dev mode or the test net
switch {
@@ -722,54 +711,30 @@ func MakeSystemNode(name, version string, relconf release.Config, extra []byte,
state.StartingNonce = 1048576 // (2**20)
case ctx.GlobalBool(DevModeFlag.Name):
- // Override the base network stack configs
- if !ctx.GlobalIsSet(DataDirFlag.Name) {
- stackConf.DataDir = filepath.Join(os.TempDir(), "/ethereum_dev_mode")
- }
- if !ctx.GlobalIsSet(MaxPeersFlag.Name) {
- stackConf.MaxPeers = 0
- }
- if !ctx.GlobalIsSet(ListenPortFlag.Name) {
- stackConf.ListenAddr = ":0"
- }
- // Override the Ethereum protocol configs
ethConf.Genesis = core.OlympicGenesisBlock()
if !ctx.GlobalIsSet(GasPriceFlag.Name) {
ethConf.GasPrice = new(big.Int)
}
- if !ctx.GlobalIsSet(WhisperEnabledFlag.Name) {
- shhEnable = true
- }
ethConf.PowTest = true
}
- // Assemble and return the protocol stack
- stack, err := node.New(stackConf)
- if err != nil {
- Fatalf("Failed to create the protocol stack: %v", err)
- }
-
- if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
- return accman, nil
- }); err != nil {
- Fatalf("Failed to register the account manager service: %v", err)
- }
if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
return eth.New(ctx, ethConf)
}); err != nil {
Fatalf("Failed to register the Ethereum service: %v", err)
}
- if shhEnable {
- if err := stack.Register(func(*node.ServiceContext) (node.Service, error) { return whisper.New(), nil }); err != nil {
- Fatalf("Failed to register the Whisper service: %v", err)
- }
- }
if err := stack.Register(func(ctx *node.ServiceContext) (node.Service, error) {
return release.NewReleaseService(ctx, relconf)
}); err != nil {
Fatalf("Failed to register the Geth release oracle service: %v", err)
}
- return stack
+}
+
+// RegisterShhService configures whisper and adds it to the given node.
+func RegisterShhService(stack *node.Node) {
+ if err := stack.Register(func(*node.ServiceContext) (node.Service, error) { return whisper.New(), nil }); err != nil {
+ Fatalf("Failed to register the Whisper service: %v", err)
+ }
}
// SetupNetwork configures the system for either the main net or some test network.
diff --git a/console/console_test.go b/console/console_test.go
index 7738d0c44..fd3459139 100644
--- a/console/console_test.go
+++ b/console/console_test.go
@@ -23,12 +23,10 @@ import (
"io/ioutil"
"math/big"
"os"
- "path/filepath"
"strings"
"testing"
"time"
- "github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/core"
"github.com/ethereum/go-ethereum/eth"
@@ -92,18 +90,16 @@ func newTester(t *testing.T, confOverride func(*eth.Config)) *tester {
if err != nil {
t.Fatalf("failed to create temporary keystore: %v", err)
}
- accman := accounts.NewPlaintextManager(filepath.Join(workspace, "keystore"))
// Create a networkless protocol stack and start an Ethereum service within
- stack, err := node.New(&node.Config{DataDir: workspace, Name: testInstance, NoDiscovery: true})
+ stack, err := node.New(&node.Config{DataDir: workspace, UseLightweightKDF: true, Name: testInstance, NoDiscovery: true})
if err != nil {
t.Fatalf("failed to create node: %v", err)
}
ethConf := &eth.Config{
- ChainConfig: &core.ChainConfig{HomesteadBlock: new(big.Int)},
- Etherbase: common.HexToAddress(testAddress),
- AccountManager: accman,
- PowTest: true,
+ ChainConfig: &core.ChainConfig{HomesteadBlock: new(big.Int)},
+ Etherbase: common.HexToAddress(testAddress),
+ PowTest: true,
}
if confOverride != nil {
confOverride(ethConf)
diff --git a/eth/backend.go b/eth/backend.go
index c8a9af6ee..9b1ca306a 100644
--- a/eth/backend.go
+++ b/eth/backend.go
@@ -83,11 +83,10 @@ type Config struct {
PowShared bool
ExtraData []byte
- AccountManager *accounts.Manager
- Etherbase common.Address
- GasPrice *big.Int
- MinerThreads int
- SolcPath string
+ Etherbase common.Address
+ GasPrice *big.Int
+ MinerThreads int
+ SolcPath string
GpoMinGasPrice *big.Int
GpoMaxGasPrice *big.Int
@@ -160,7 +159,7 @@ func New(ctx *node.ServiceContext, config *Config) (*Ethereum, error) {
chainDb: chainDb,
dappDb: dappDb,
eventMux: ctx.EventMux,
- accountManager: config.AccountManager,
+ accountManager: ctx.AccountManager,
pow: pow,
shutdownChan: make(chan bool),
stopDbUpgrade: stopDbUpgrade,
diff --git a/node/config.go b/node/config.go
index bc9fec618..432da7015 100644
--- a/node/config.go
+++ b/node/config.go
@@ -27,6 +27,7 @@ import (
"runtime"
"strings"
+ "github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/common"
"github.com/ethereum/go-ethereum/crypto"
"github.com/ethereum/go-ethereum/logger"
@@ -36,10 +37,11 @@ import (
)
var (
- datadirPrivateKey = "nodekey" // Path within the datadir to the node's private key
- datadirStaticNodes = "static-nodes.json" // Path within the datadir to the static node list
- datadirTrustedNodes = "trusted-nodes.json" // Path within the datadir to the trusted node list
- datadirNodeDatabase = "nodes" // Path within the datadir to store the node infos
+ datadirPrivateKey = "nodekey" // Path within the datadir to the node's private key
+ datadirDefaultKeyStore = "keystore" // Path within the datadir to the keystore
+ datadirStaticNodes = "static-nodes.json" // Path within the datadir to the static node list
+ datadirTrustedNodes = "trusted-nodes.json" // Path within the datadir to the trusted node list
+ datadirNodeDatabase = "nodes" // Path within the datadir to store the node infos
)
// Config represents a small collection of configuration values to fine tune the
@@ -53,6 +55,19 @@ type Config struct {
// in memory.
DataDir string
+ // KeyStoreDir is the file system folder that contains private keys. The directory can
+ // be specified as a relative path, in which case it is resolved relative to the
+ // current directory.
+ //
+ // If KeyStoreDir is empty, the default location is the "keystore" subdirectory of
+ // DataDir. If DataDir is unspecified and KeyStoreDir is empty, an ephemeral directory
+ // is created by New and destroyed when the node is stopped.
+ KeyStoreDir string
+
+ // UseLightweightKDF lowers the memory and CPU requirements of the key store
+ // scrypt KDF at the expense of security.
+ UseLightweightKDF bool
+
// IPCPath is the requested location to place the IPC endpoint. If the path is
// a simple file name, it is placed inside the data directory (or on the root
// pipe path on Windows), whereas if it's a resolvable path name (absolute or
@@ -278,3 +293,38 @@ func (c *Config) parsePersistentNodes(file string) []*discover.Node {
}
return nodes
}
+
+func makeAccountManager(conf *Config) (am *accounts.Manager, ephemeralKeystore string, err error) {
+ scryptN := accounts.StandardScryptN
+ scryptP := accounts.StandardScryptP
+ if conf.UseLightweightKDF {
+ scryptN = accounts.LightScryptN
+ scryptP = accounts.LightScryptP
+ }
+
+ var keydir string
+ switch {
+ case filepath.IsAbs(conf.KeyStoreDir):
+ keydir = conf.KeyStoreDir
+ case conf.DataDir != "":
+ if conf.KeyStoreDir == "" {
+ keydir = filepath.Join(conf.DataDir, datadirDefaultKeyStore)
+ } else {
+ keydir, err = filepath.Abs(conf.KeyStoreDir)
+ }
+ case conf.KeyStoreDir != "":
+ keydir, err = filepath.Abs(conf.KeyStoreDir)
+ default:
+ // There is no datadir.
+ keydir, err = ioutil.TempDir("", "go-ethereum-keystore")
+ ephemeralKeystore = keydir
+ }
+ if err != nil {
+ return nil, "", err
+ }
+ if err := os.MkdirAll(keydir, 0700); err != nil {
+ return nil, "", err
+ }
+
+ return accounts.NewManager(keydir, scryptN, scryptP), ephemeralKeystore, nil
+}
diff --git a/node/node.go b/node/node.go
index ac8a7e8f0..f3be2f763 100644
--- a/node/node.go
+++ b/node/node.go
@@ -26,6 +26,7 @@ import (
"sync"
"syscall"
+ "github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/internal/debug"
"github.com/ethereum/go-ethereum/logger"
@@ -49,6 +50,9 @@ type Node struct {
datadir string // Path to the currently used data directory
eventmux *event.TypeMux // Event multiplexer used between the services of a stack
+ accman *accounts.Manager
+ ephemeralKeystore string // if non-empty, the key directory that will be removed by Stop
+
serverConfig p2p.Config
server *p2p.Server // Currently running P2P networking layer
@@ -90,13 +94,20 @@ func New(conf *Config) (*Node, error) {
return nil, err
}
}
+ am, ephemeralKeystore, err := makeAccountManager(conf)
+ if err != nil {
+ return nil, err
+ }
+
// Assemble the networking layer and the node itself
nodeDbPath := ""
if conf.DataDir != "" {
nodeDbPath = filepath.Join(conf.DataDir, datadirNodeDatabase)
}
return &Node{
- datadir: conf.DataDir,
+ datadir: conf.DataDir,
+ accman: am,
+ ephemeralKeystore: ephemeralKeystore,
serverConfig: p2p.Config{
PrivateKey: conf.NodeKey(),
Name: conf.Name,
@@ -156,9 +167,10 @@ func (n *Node) Start() error {
for _, constructor := range n.serviceFuncs {
// Create a new context for the particular service
ctx := &ServiceContext{
- datadir: n.datadir,
- services: make(map[reflect.Type]Service),
- EventMux: n.eventmux,
+ datadir: n.datadir,
+ services: make(map[reflect.Type]Service),
+ EventMux: n.eventmux,
+ AccountManager: n.accman,
}
for kind, s := range services { // copy needed for threaded access
ctx.services[kind] = s
@@ -473,9 +485,18 @@ func (n *Node) Stop() error {
n.server = nil
close(n.stop)
+ // Remove the keystore if it was created ephemerally.
+ var keystoreErr error
+ if n.ephemeralKeystore != "" {
+ keystoreErr = os.RemoveAll(n.ephemeralKeystore)
+ }
+
if len(failure.Services) > 0 {
return failure
}
+ if keystoreErr != nil {
+ return keystoreErr
+ }
return nil
}
@@ -548,6 +569,11 @@ func (n *Node) DataDir() string {
return n.datadir
}
+// AccountManager retrieves the account manager used by the protocol stack.
+func (n *Node) AccountManager() *accounts.Manager {
+ return n.accman
+}
+
// IPCEndpoint retrieves the current IPC endpoint used by the protocol stack.
func (n *Node) IPCEndpoint() string {
return n.ipcEndpoint
diff --git a/node/service.go b/node/service.go
index 4d9a6e42c..51531466b 100644
--- a/node/service.go
+++ b/node/service.go
@@ -20,6 +20,7 @@ import (
"path/filepath"
"reflect"
+ "github.com/ethereum/go-ethereum/accounts"
"github.com/ethereum/go-ethereum/ethdb"
"github.com/ethereum/go-ethereum/event"
"github.com/ethereum/go-ethereum/p2p"
@@ -30,9 +31,10 @@ import (
// the protocol stack, that is passed to all constructors to be optionally used;
// as well as utility methods to operate on the service environment.
type ServiceContext struct {
- datadir string // Data directory for protocol persistence
- services map[reflect.Type]Service // Index of the already constructed services
- EventMux *event.TypeMux // Event multiplexer used for decoupled notifications
+ datadir string // Data directory for protocol persistence
+ services map[reflect.Type]Service // Index of the already constructed services
+ EventMux *event.TypeMux // Event multiplexer used for decoupled notifications
+ AccountManager *accounts.Manager // Account manager created by the node.
}
// OpenDatabase opens an existing database with the given name (or creates one