From 312263c7d9457fe7c24aac8e42a4cf2efc6ccd8e Mon Sep 17 00:00:00 2001 From: Felix Lange Date: Mon, 15 Aug 2016 18:38:32 +0200 Subject: 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. --- node/config.go | 58 +++++++++++++++++++++++++++++++++++++++++++++++++++++---- node/node.go | 34 +++++++++++++++++++++++++++++---- node/service.go | 8 +++++--- 3 files changed, 89 insertions(+), 11 deletions(-) (limited to 'node') 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 -- cgit v1.2.3