aboutsummaryrefslogtreecommitdiffstats
path: root/accounts/key_store_plain.go
diff options
context:
space:
mode:
authorFelix Lange <fjl@twurst.com>2016-03-03 08:15:42 +0800
committerFelix Lange <fjl@twurst.com>2016-04-12 21:58:07 +0800
commita9f26dcd0d14c0cb9f309ebccf81e8f741fc4636 (patch)
tree1a1e269194f3698737b0c1dbaf918c4e8dbae347 /accounts/key_store_plain.go
parentef63e9af55fcfe3255dddec3197bd8a807152c66 (diff)
downloadgo-tangerine-a9f26dcd0d14c0cb9f309ebccf81e8f741fc4636.tar
go-tangerine-a9f26dcd0d14c0cb9f309ebccf81e8f741fc4636.tar.gz
go-tangerine-a9f26dcd0d14c0cb9f309ebccf81e8f741fc4636.tar.bz2
go-tangerine-a9f26dcd0d14c0cb9f309ebccf81e8f741fc4636.tar.lz
go-tangerine-a9f26dcd0d14c0cb9f309ebccf81e8f741fc4636.tar.xz
go-tangerine-a9f26dcd0d14c0cb9f309ebccf81e8f741fc4636.tar.zst
go-tangerine-a9f26dcd0d14c0cb9f309ebccf81e8f741fc4636.zip
accounts: cache key addresses
In order to avoid disk thrashing for Accounts and HasAccount, address->key file mappings are now cached in memory. This makes it no longer necessary to keep the key address in the file name. The address of each key is derived from file content instead. There are minor user-visible changes: - "geth account list" now reports key file paths alongside the address. - If multiple keys are present for an address, unlocking by address is not possible. Users are directed to remove the duplicate files instead. Unlocking by index is still possible. - Key files are overwritten written in place when updating the password.
Diffstat (limited to 'accounts/key_store_plain.go')
-rw-r--r--accounts/key_store_plain.go165
1 files changed, 14 insertions, 151 deletions
diff --git a/accounts/key_store_plain.go b/accounts/key_store_plain.go
index ca1d89757..ceb455281 100644
--- a/accounts/key_store_plain.go
+++ b/accounts/key_store_plain.go
@@ -17,14 +17,10 @@
package accounts
import (
- "encoding/hex"
"encoding/json"
"fmt"
- "io"
- "io/ioutil"
"os"
"path/filepath"
- "time"
"github.com/ethereum/go-ethereum/common"
)
@@ -33,167 +29,34 @@ type keyStorePlain struct {
keysDirPath string
}
-func newKeyStorePlain(path string) keyStore {
- return &keyStorePlain{path}
-}
-
-func (ks keyStorePlain) GenerateNewKey(rand io.Reader, auth string) (key *Key, err error) {
- return generateNewKeyDefault(ks, rand, auth)
-}
-
-func generateNewKeyDefault(ks keyStore, rand io.Reader, auth string) (key *Key, err error) {
- defer func() {
- if r := recover(); r != nil {
- err = fmt.Errorf("GenerateNewKey error: %v", r)
- }
- }()
- key = NewKey(rand)
- err = ks.StoreKey(key, auth)
- return key, err
-}
-
-func (ks keyStorePlain) GetKey(keyAddr common.Address, auth string) (*Key, error) {
- keyjson, err := getKeyFile(ks.keysDirPath, keyAddr)
+func (ks keyStorePlain) GetKey(addr common.Address, filename, auth string) (*Key, error) {
+ fd, err := os.Open(filename)
if err != nil {
return nil, err
}
+ defer fd.Close()
key := new(Key)
- if err := json.Unmarshal(keyjson, key); err != nil {
+ if err := json.NewDecoder(fd).Decode(key); err != nil {
return nil, err
}
- return key, nil
-}
-
-func (ks keyStorePlain) GetKeyAddresses() (addresses []common.Address, err error) {
- return getKeyAddresses(ks.keysDirPath)
-}
-
-func (ks keyStorePlain) Cleanup(keyAddr common.Address) (err error) {
- return cleanup(ks.keysDirPath, keyAddr)
-}
-
-func (ks keyStorePlain) StoreKey(key *Key, auth string) (err error) {
- keyJSON, err := json.Marshal(key)
- if err != nil {
- return
- }
- err = writeKeyFile(key.Address, ks.keysDirPath, keyJSON)
- return
-}
-
-func (ks keyStorePlain) DeleteKey(keyAddr common.Address, auth string) (err error) {
- return deleteKey(ks.keysDirPath, keyAddr)
-}
-
-func deleteKey(keysDirPath string, keyAddr common.Address) (err error) {
- var path string
- path, err = getKeyFilePath(keysDirPath, keyAddr)
- if err == nil {
- addrHex := hex.EncodeToString(keyAddr[:])
- if path == filepath.Join(keysDirPath, addrHex, addrHex) {
- path = filepath.Join(keysDirPath, addrHex)
- }
- err = os.RemoveAll(path)
- }
- return
-}
-
-func getKeyFilePath(keysDirPath string, keyAddr common.Address) (keyFilePath string, err error) {
- addrHex := hex.EncodeToString(keyAddr[:])
- matches, err := filepath.Glob(filepath.Join(keysDirPath, fmt.Sprintf("*--%s", addrHex)))
- if len(matches) > 0 {
- if err == nil {
- keyFilePath = matches[len(matches)-1]
- }
- return
- }
- keyFilePath = filepath.Join(keysDirPath, addrHex, addrHex)
- _, err = os.Stat(keyFilePath)
- return
-}
-
-func cleanup(keysDirPath string, keyAddr common.Address) (err error) {
- fileInfos, err := ioutil.ReadDir(keysDirPath)
- if err != nil {
- return
- }
- var paths []string
- account := hex.EncodeToString(keyAddr[:])
- for _, fileInfo := range fileInfos {
- path := filepath.Join(keysDirPath, fileInfo.Name())
- if len(path) >= 40 {
- addr := path[len(path)-40 : len(path)]
- if addr == account {
- if path == filepath.Join(keysDirPath, addr, addr) {
- path = filepath.Join(keysDirPath, addr)
- }
- paths = append(paths, path)
- }
- }
- }
- if len(paths) > 1 {
- for i := 0; err == nil && i < len(paths)-1; i++ {
- err = os.RemoveAll(paths[i])
- if err != nil {
- break
- }
- }
- }
- return
-}
-
-func getKeyFile(keysDirPath string, keyAddr common.Address) (fileContent []byte, err error) {
- var keyFilePath string
- keyFilePath, err = getKeyFilePath(keysDirPath, keyAddr)
- if err == nil {
- fileContent, err = ioutil.ReadFile(keyFilePath)
+ if key.Address != addr {
+ return nil, fmt.Errorf("key content mismatch: have address %x, want %x", key.Address, addr)
}
- return
+ return key, nil
}
-func writeKeyFile(addr common.Address, keysDirPath string, content []byte) (err error) {
- filename := keyFileName(addr)
- // read, write and dir search for user
- err = os.MkdirAll(keysDirPath, 0700)
+func (ks keyStorePlain) StoreKey(filename string, key *Key, auth string) error {
+ content, err := json.Marshal(key)
if err != nil {
return err
}
- // read, write for user
- return ioutil.WriteFile(filepath.Join(keysDirPath, filename), content, 0600)
+ return writeKeyFile(filename, content)
}
-// keyFilePath implements the naming convention for keyfiles:
-// UTC--<created_at UTC ISO8601>-<address hex>
-func keyFileName(keyAddr common.Address) string {
- ts := time.Now().UTC()
- return fmt.Sprintf("UTC--%s--%s", toISO8601(ts), hex.EncodeToString(keyAddr[:]))
-}
-
-func toISO8601(t time.Time) string {
- var tz string
- name, offset := t.Zone()
- if name == "UTC" {
- tz = "Z"
+func (ks keyStorePlain) JoinPath(filename string) string {
+ if filepath.IsAbs(filename) {
+ return filename
} else {
- tz = fmt.Sprintf("%03d00", offset/3600)
- }
- return fmt.Sprintf("%04d-%02d-%02dT%02d-%02d-%02d.%09d%s", t.Year(), t.Month(), t.Day(), t.Hour(), t.Minute(), t.Second(), t.Nanosecond(), tz)
-}
-
-func getKeyAddresses(keysDirPath string) (addresses []common.Address, err error) {
- fileInfos, err := ioutil.ReadDir(keysDirPath)
- if err != nil {
- return nil, err
- }
- for _, fileInfo := range fileInfos {
- filename := fileInfo.Name()
- if len(filename) >= 40 {
- addr := filename[len(filename)-40 : len(filename)]
- address, err := hex.DecodeString(addr)
- if err == nil {
- addresses = append(addresses, common.BytesToAddress(address))
- }
- }
+ return filepath.Join(ks.keysDirPath, filename)
}
- return addresses, err
}