diff --git a/cmd/statusd/utils.go b/cmd/statusd/utils.go index 50c984866..8aa485908 100644 --- a/cmd/statusd/utils.go +++ b/cmd/statusd/utils.go @@ -1307,29 +1307,9 @@ func startTestNode(t *testing.T) <-chan struct{} { syncRequired = true } - // prepare node directory - if err := os.MkdirAll(filepath.Join(geth.TestDataDir, "testnet", "keystore"), os.ModePerm); err != nil { - panic(err) - } - - // import test account (with test ether on it) - importTestAccount := func(accountFile string) error { - dst := filepath.Join(geth.TestDataDir, "keystore", accountFile) - if _, err := os.Stat(dst); os.IsNotExist(err) { - err = geth.CopyFile(dst, filepath.Join(geth.RootDir, "data", accountFile)) - if err != nil { - panic(err) - } - } - - return nil - } - if err := importTestAccount("test-account1.pk"); err != nil { - panic(err) - } - if err := importTestAccount("test-account2.pk"); err != nil { - panic(err) - } + // inject test accounts + geth.ImportTestAccount(filepath.Join(geth.TestDataDir, "keystore"), "test-account1.pk") + geth.ImportTestAccount(filepath.Join(geth.TestDataDir, "keystore"), "test-account2.pk") waitForNodeStart := make(chan struct{}, 1) geth.SetDefaultNodeNotificationHandler(func(jsonEvent string) { diff --git a/geth/node.go b/geth/node.go index 19af38edc..3397e6f19 100644 --- a/geth/node.go +++ b/geth/node.go @@ -63,6 +63,10 @@ func MakeNode(config *params.NodeConfig) *Node { if err := os.MkdirAll(filepath.Join(config.DataDir), os.ModePerm); err != nil { Fatalf(err) } + // make sure keys directory exists + if err := os.MkdirAll(filepath.Join(config.KeyStoreDir), os.ModePerm); err != nil { + Fatalf(err) + } // setup logging glog.CopyStandardLogTo("INFO") @@ -74,6 +78,7 @@ func MakeNode(config *params.NodeConfig) *Node { // configure required node (should you need to update node's config, e.g. add bootstrap nodes, see node.Config) stackConfig := &node.Config{ DataDir: config.DataDir, + KeyStoreDir: config.KeyStoreDir, UseLightweightKDF: true, Name: config.Name, Version: config.Version, diff --git a/geth/params/config.go b/geth/params/config.go index b4f2782f3..2bb1e1a0b 100644 --- a/geth/params/config.go +++ b/geth/params/config.go @@ -129,6 +129,10 @@ type NodeConfig struct { // DataDir is the file system folder the node should use for any data storage needs. DataDir string + // KeyStoreDir is the file system folder that contains private keys. + // If KeyStoreDir is empty, the default location is the "keystore" subdirectory of DataDir. + KeyStoreDir string + // PrivateKeyFile is a filename with node ID (private key) // This file should contain a valid secp256k1 private key that will be used for both // remote peer identification as well as network traffic encryption. @@ -223,7 +227,6 @@ func NewNodeConfig(dataDir string, networkId int) (*NodeConfig, error) { }, WhisperConfig: &WhisperConfig{ Enabled: true, - DataDir: filepath.Join(dataDir, "wnode"), Port: WhisperPort, MinimumPoW: WhisperMinimumPoW, TTL: WhisperTTL, @@ -231,12 +234,32 @@ func NewNodeConfig(dataDir string, networkId int) (*NodeConfig, error) { SwarmConfig: &SwarmConfig{}, } + // auto-populate some dependent values nodeConfig.populateChainConfig() + nodeConfig.populateDirs() return nodeConfig, nil } -// populateChainConfig does necessary adjustments to config object (depending on network node will be runnin on) +// populateDirs updates directories that should be wrt to DataDir +func (c *NodeConfig) populateDirs() { + makeSubDirPath := func(baseDir, subDir string) string { + if len(baseDir) == 0 { + return "" + } + + return filepath.Join(baseDir, subDir) + } + if len(c.KeyStoreDir) == 0 { + c.KeyStoreDir = makeSubDirPath(c.DataDir, KeyStoreDir) + } + + if len(c.WhisperConfig.DataDir) == 0 { + c.WhisperConfig.DataDir = makeSubDirPath(c.DataDir, WhisperDataDir) + } +} + +// populateChainConfig does necessary adjustments to config object (depending on network node will be running on) func (c *NodeConfig) populateChainConfig() { c.TestNet = false if c.NetworkId == TestNetworkId { @@ -298,6 +321,7 @@ func LoadNodeConfig(configJSON string) (*NodeConfig, error) { // repopulate nodeConfig.populateChainConfig() + nodeConfig.populateDirs() if len(nodeConfig.DataDir) == 0 { return nil, ErrMissingDataDir diff --git a/geth/params/config_test.go b/geth/params/config_test.go index 05943d568..c64603a82 100644 --- a/geth/params/config_test.go +++ b/geth/params/config_test.go @@ -75,6 +75,53 @@ var loadConfigTestCases = []struct { } }, }, + { + `use default KeyStoreDir`, + `{ + "NetworkId": 3, + "DataDir": "$TMPDIR" + }`, + func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) { + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + if _, err := os.Stat(dataDir); os.IsNotExist(err) { + t.Fatalf("data directory doesn't exist: %s", dataDir) + } + + expectedDataDir := dataDir + if nodeConfig.DataDir != expectedDataDir { + t.Fatalf("incorrect DataDir used, expected: %v, got: %v", expectedDataDir, nodeConfig.DataDir) + } + + expectedKeyStoreDir := filepath.Join(dataDir, params.KeyStoreDir) + if nodeConfig.KeyStoreDir != expectedKeyStoreDir { + t.Fatalf("incorrect KeyStoreDir used, expected: %v, got: %v", expectedKeyStoreDir, nodeConfig.KeyStoreDir) + } + }, + }, + { + `use non-default KeyStoreDir`, + `{ + "NetworkId": 3, + "DataDir": "$TMPDIR", + "KeyStoreDir": "/foo/bar" + }`, + func(t *testing.T, dataDir string, nodeConfig *params.NodeConfig, err error) { + if err != nil { + t.Fatalf("unexpected error: %v", err) + } + expectedDataDir := dataDir + if nodeConfig.DataDir != expectedDataDir { + t.Fatalf("incorrect DataDir used, expected: %v, got: %v", expectedDataDir, nodeConfig.DataDir) + } + + expectedKeyStoreDir := "/foo/bar" + if nodeConfig.KeyStoreDir != expectedKeyStoreDir { + t.Fatalf("incorrect KeyStoreDir used, expected: %v, got: %v", expectedKeyStoreDir, nodeConfig.KeyStoreDir) + } + }, + }, { `test parameter overriding`, `{ diff --git a/geth/params/defaults.go b/geth/params/defaults.go index 0d4688272..7c18c83e0 100644 --- a/geth/params/defaults.go +++ b/geth/params/defaults.go @@ -13,6 +13,9 @@ const ( // DataDir is default data directory used by statusd executable DataDir = "statusd-data" + // KeyStoreDir is default directory where private keys are stored, relative to DataDir + KeyStoreDir = "keystore" + // IPCFile is filename of exposed IPC RPC Server IPCFile = "geth.ipc" @@ -54,6 +57,9 @@ const ( // LogLevel defines the minimum log level to report LogLevel = "INFO" + // WhisperDataDir is directory where Whisper data is stored, relative to DataDir + WhisperDataDir = "wnode" + // WhisperPort is Whisper node listening port WhisperPort = 30379 diff --git a/geth/params/testdata/config.testnet.json b/geth/params/testdata/config.testnet.json index 911b296cf..a9a92d011 100755 --- a/geth/params/testdata/config.testnet.json +++ b/geth/params/testdata/config.testnet.json @@ -2,6 +2,7 @@ "TestNet": true, "NetworkId": 3, "DataDir": "$TMPDIR", + "KeyStoreDir": "$TMPDIR/keystore", "NodeKeyFile": "", "Name": "StatusIM", "Version": "$VERSION", diff --git a/geth/utils.go b/geth/utils.go index 609269a5b..6a84615e2 100644 --- a/geth/utils.go +++ b/geth/utils.go @@ -177,10 +177,11 @@ func PrepareTestNode() (err error) { } // start geth node and wait for it to initialize - config, err := params.NewNodeConfig(TestDataDir, params.TestNetworkId) + config, err := params.NewNodeConfig(filepath.Join(TestDataDir, "data"), params.TestNetworkId) if err != nil { return err } + config.KeyStoreDir = filepath.Join(TestDataDir, "keystore") config.HTTPPort = testConfig.Node.HTTPPort // to avoid conflicts with running app, using different port in tests config.WSPort = testConfig.Node.WSPort // ditto config.LogEnabled = true