diff options
author | Felix Lange <fjl@twurst.com> | 2016-03-03 08:15:42 +0800 |
---|---|---|
committer | Felix Lange <fjl@twurst.com> | 2016-04-12 21:58:07 +0800 |
commit | a9f26dcd0d14c0cb9f309ebccf81e8f741fc4636 (patch) | |
tree | 1a1e269194f3698737b0c1dbaf918c4e8dbae347 /accounts/key_store_plain.go | |
parent | ef63e9af55fcfe3255dddec3197bd8a807152c66 (diff) | |
download | go-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.go | 165 |
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 } |