| 
									
										
										
										
											2017-04-14 10:29:00 +02:00
										 |  |  | // Copyright 2017 The go-ethereum Authors | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | // This file is part of the go-ethereum library. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // The go-ethereum library is free software: you can redistribute it and/or modify | 
					
						
							|  |  |  | // it under the terms of the GNU Lesser General Public License as published by | 
					
						
							|  |  |  | // the Free Software Foundation, either version 3 of the License, or | 
					
						
							|  |  |  | // (at your option) any later version. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // The go-ethereum library is distributed in the hope that it will be useful, | 
					
						
							|  |  |  | // but WITHOUT ANY WARRANTY; without even the implied warranty of | 
					
						
							|  |  |  | // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | 
					
						
							|  |  |  | // GNU Lesser General Public License for more details. | 
					
						
							|  |  |  | // | 
					
						
							|  |  |  | // You should have received a copy of the GNU Lesser General Public License | 
					
						
							|  |  |  | // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>. | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-24 11:49:20 +02:00
										 |  |  | package keystore | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | import ( | 
					
						
							|  |  |  | 	"bufio" | 
					
						
							|  |  |  | 	"encoding/json" | 
					
						
							|  |  |  | 	"fmt" | 
					
						
							|  |  |  | 	"os" | 
					
						
							|  |  |  | 	"path/filepath" | 
					
						
							|  |  |  | 	"sort" | 
					
						
							|  |  |  | 	"strings" | 
					
						
							|  |  |  | 	"sync" | 
					
						
							|  |  |  | 	"time" | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-24 11:49:20 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/accounts" | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | 	"github.com/ethereum/go-ethereum/common" | 
					
						
							| 
									
										
										
										
											2017-02-22 14:10:07 +02:00
										 |  |  | 	"github.com/ethereum/go-ethereum/log" | 
					
						
							| 
									
										
										
										
											2017-10-09 12:40:50 +02:00
										 |  |  | 	"gopkg.in/fatih/set.v0" | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | ) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // Minimum amount of time between cache reloads. This limit applies if the platform does | 
					
						
							|  |  |  | // not support change notifications. It also applies if the keystore directory does not | 
					
						
							|  |  |  | // exist yet, the code will attempt to create a watcher at most this often. | 
					
						
							|  |  |  | const minReloadInterval = 2 * time.Second | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-07 12:47:34 +02:00
										 |  |  | type accountsByURL []accounts.Account | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-07 12:47:34 +02:00
										 |  |  | func (s accountsByURL) Len() int           { return len(s) } | 
					
						
							| 
									
										
										
										
											2017-02-08 15:53:02 +02:00
										 |  |  | func (s accountsByURL) Less(i, j int) bool { return s[i].URL.Cmp(s[j].URL) < 0 } | 
					
						
							| 
									
										
										
										
											2017-02-07 12:47:34 +02:00
										 |  |  | func (s accountsByURL) Swap(i, j int)      { s[i], s[j] = s[j], s[i] } | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | 
 | 
					
						
							|  |  |  | // AmbiguousAddrError is returned when attempting to unlock | 
					
						
							|  |  |  | // an address for which more than one file exists. | 
					
						
							|  |  |  | type AmbiguousAddrError struct { | 
					
						
							|  |  |  | 	Addr    common.Address | 
					
						
							| 
									
										
										
										
											2017-01-24 11:49:20 +02:00
										 |  |  | 	Matches []accounts.Account | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | func (err *AmbiguousAddrError) Error() string { | 
					
						
							|  |  |  | 	files := "" | 
					
						
							|  |  |  | 	for i, a := range err.Matches { | 
					
						
							| 
									
										
										
										
											2017-02-08 15:53:02 +02:00
										 |  |  | 		files += a.URL.Path | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | 		if i < len(err.Matches)-1 { | 
					
						
							|  |  |  | 			files += ", " | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return fmt.Sprintf("multiple keys match address (%s)", files) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-07 12:47:34 +02:00
										 |  |  | // accountCache is a live index of all accounts in the keystore. | 
					
						
							|  |  |  | type accountCache struct { | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | 	keydir   string | 
					
						
							|  |  |  | 	watcher  *watcher | 
					
						
							|  |  |  | 	mu       sync.Mutex | 
					
						
							| 
									
										
										
										
											2017-02-07 12:47:34 +02:00
										 |  |  | 	all      accountsByURL | 
					
						
							| 
									
										
										
										
											2017-01-24 11:49:20 +02:00
										 |  |  | 	byAddr   map[common.Address][]accounts.Account | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | 	throttle *time.Timer | 
					
						
							| 
									
										
										
										
											2017-02-07 12:47:34 +02:00
										 |  |  | 	notify   chan struct{} | 
					
						
							| 
									
										
										
										
											2017-10-09 12:40:50 +02:00
										 |  |  | 	fileC    fileCache | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-07 12:47:34 +02:00
										 |  |  | func newAccountCache(keydir string) (*accountCache, chan struct{}) { | 
					
						
							|  |  |  | 	ac := &accountCache{ | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | 		keydir: keydir, | 
					
						
							| 
									
										
										
										
											2017-01-24 11:49:20 +02:00
										 |  |  | 		byAddr: make(map[common.Address][]accounts.Account), | 
					
						
							| 
									
										
										
										
											2017-02-07 12:47:34 +02:00
										 |  |  | 		notify: make(chan struct{}, 1), | 
					
						
							| 
									
										
										
										
											2017-10-09 12:40:50 +02:00
										 |  |  | 		fileC:  fileCache{all: set.NewNonTS()}, | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | 	ac.watcher = newWatcher(ac) | 
					
						
							| 
									
										
										
										
											2017-02-07 12:47:34 +02:00
										 |  |  | 	return ac, ac.notify | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-07 12:47:34 +02:00
										 |  |  | func (ac *accountCache) accounts() []accounts.Account { | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | 	ac.maybeReload() | 
					
						
							|  |  |  | 	ac.mu.Lock() | 
					
						
							|  |  |  | 	defer ac.mu.Unlock() | 
					
						
							| 
									
										
										
										
											2017-01-24 11:49:20 +02:00
										 |  |  | 	cpy := make([]accounts.Account, len(ac.all)) | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | 	copy(cpy, ac.all) | 
					
						
							|  |  |  | 	return cpy | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-07 12:47:34 +02:00
										 |  |  | func (ac *accountCache) hasAddress(addr common.Address) bool { | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | 	ac.maybeReload() | 
					
						
							|  |  |  | 	ac.mu.Lock() | 
					
						
							|  |  |  | 	defer ac.mu.Unlock() | 
					
						
							|  |  |  | 	return len(ac.byAddr[addr]) > 0 | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-07 12:47:34 +02:00
										 |  |  | func (ac *accountCache) add(newAccount accounts.Account) { | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | 	ac.mu.Lock() | 
					
						
							|  |  |  | 	defer ac.mu.Unlock() | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-08 15:53:02 +02:00
										 |  |  | 	i := sort.Search(len(ac.all), func(i int) bool { return ac.all[i].URL.Cmp(newAccount.URL) >= 0 }) | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | 	if i < len(ac.all) && ac.all[i] == newAccount { | 
					
						
							|  |  |  | 		return | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// newAccount is not in the cache. | 
					
						
							| 
									
										
										
										
											2017-01-24 11:49:20 +02:00
										 |  |  | 	ac.all = append(ac.all, accounts.Account{}) | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | 	copy(ac.all[i+1:], ac.all[i:]) | 
					
						
							|  |  |  | 	ac.all[i] = newAccount | 
					
						
							|  |  |  | 	ac.byAddr[newAccount.Address] = append(ac.byAddr[newAccount.Address], newAccount) | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // note: removed needs to be unique here (i.e. both File and Address must be set). | 
					
						
							| 
									
										
										
										
											2017-02-07 12:47:34 +02:00
										 |  |  | func (ac *accountCache) delete(removed accounts.Account) { | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | 	ac.mu.Lock() | 
					
						
							|  |  |  | 	defer ac.mu.Unlock() | 
					
						
							| 
									
										
										
										
											2017-02-07 12:47:34 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | 	ac.all = removeAccount(ac.all, removed) | 
					
						
							|  |  |  | 	if ba := removeAccount(ac.byAddr[removed.Address], removed); len(ba) == 0 { | 
					
						
							|  |  |  | 		delete(ac.byAddr, removed.Address) | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		ac.byAddr[removed.Address] = ba | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-09 12:40:50 +02:00
										 |  |  | // deleteByFile removes an account referenced by the given path. | 
					
						
							|  |  |  | func (ac *accountCache) deleteByFile(path string) { | 
					
						
							|  |  |  | 	ac.mu.Lock() | 
					
						
							|  |  |  | 	defer ac.mu.Unlock() | 
					
						
							|  |  |  | 	i := sort.Search(len(ac.all), func(i int) bool { return ac.all[i].URL.Path >= path }) | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if i < len(ac.all) && ac.all[i].URL.Path == path { | 
					
						
							|  |  |  | 		removed := ac.all[i] | 
					
						
							|  |  |  | 		ac.all = append(ac.all[:i], ac.all[i+1:]...) | 
					
						
							|  |  |  | 		if ba := removeAccount(ac.byAddr[removed.Address], removed); len(ba) == 0 { | 
					
						
							|  |  |  | 			delete(ac.byAddr, removed.Address) | 
					
						
							|  |  |  | 		} else { | 
					
						
							|  |  |  | 			ac.byAddr[removed.Address] = ba | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-01-24 11:49:20 +02:00
										 |  |  | func removeAccount(slice []accounts.Account, elem accounts.Account) []accounts.Account { | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | 	for i := range slice { | 
					
						
							|  |  |  | 		if slice[i] == elem { | 
					
						
							|  |  |  | 			return append(slice[:i], slice[i+1:]...) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return slice | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | // find returns the cached account for address if there is a unique match. | 
					
						
							| 
									
										
										
										
											2017-01-24 11:49:20 +02:00
										 |  |  | // The exact matching rules are explained by the documentation of accounts.Account. | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | // Callers must hold ac.mu. | 
					
						
							| 
									
										
										
										
											2017-02-07 12:47:34 +02:00
										 |  |  | func (ac *accountCache) find(a accounts.Account) (accounts.Account, error) { | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | 	// Limit search to address candidates if possible. | 
					
						
							|  |  |  | 	matches := ac.all | 
					
						
							|  |  |  | 	if (a.Address != common.Address{}) { | 
					
						
							|  |  |  | 		matches = ac.byAddr[a.Address] | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-02-08 15:53:02 +02:00
										 |  |  | 	if a.URL.Path != "" { | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | 		// If only the basename is specified, complete the path. | 
					
						
							| 
									
										
										
										
											2017-02-08 15:53:02 +02:00
										 |  |  | 		if !strings.ContainsRune(a.URL.Path, filepath.Separator) { | 
					
						
							|  |  |  | 			a.URL.Path = filepath.Join(ac.keydir, a.URL.Path) | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 		for i := range matches { | 
					
						
							| 
									
										
										
										
											2017-01-24 11:49:20 +02:00
										 |  |  | 			if matches[i].URL == a.URL { | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | 				return matches[i], nil | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		if (a.Address == common.Address{}) { | 
					
						
							| 
									
										
										
										
											2017-01-24 11:49:20 +02:00
										 |  |  | 			return accounts.Account{}, ErrNoMatch | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	switch len(matches) { | 
					
						
							|  |  |  | 	case 1: | 
					
						
							|  |  |  | 		return matches[0], nil | 
					
						
							|  |  |  | 	case 0: | 
					
						
							| 
									
										
										
										
											2017-01-24 11:49:20 +02:00
										 |  |  | 		return accounts.Account{}, ErrNoMatch | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | 	default: | 
					
						
							| 
									
										
										
										
											2017-01-24 11:49:20 +02:00
										 |  |  | 		err := &AmbiguousAddrError{Addr: a.Address, Matches: make([]accounts.Account, len(matches))} | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | 		copy(err.Matches, matches) | 
					
						
							| 
									
										
										
										
											2017-10-09 12:40:50 +02:00
										 |  |  | 		sort.Sort(accountsByURL(err.Matches)) | 
					
						
							| 
									
										
										
										
											2017-01-24 11:49:20 +02:00
										 |  |  | 		return accounts.Account{}, err | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | 	} | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-07 12:47:34 +02:00
										 |  |  | func (ac *accountCache) maybeReload() { | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | 	ac.mu.Lock() | 
					
						
							| 
									
										
										
										
											2017-02-07 12:47:34 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | 	if ac.watcher.running { | 
					
						
							| 
									
										
										
										
											2017-10-09 12:40:50 +02:00
										 |  |  | 		ac.mu.Unlock() | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | 		return // A watcher is running and will keep the cache up-to-date. | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	if ac.throttle == nil { | 
					
						
							|  |  |  | 		ac.throttle = time.NewTimer(0) | 
					
						
							|  |  |  | 	} else { | 
					
						
							|  |  |  | 		select { | 
					
						
							|  |  |  | 		case <-ac.throttle.C: | 
					
						
							|  |  |  | 		default: | 
					
						
							| 
									
										
										
										
											2017-10-09 12:40:50 +02:00
										 |  |  | 			ac.mu.Unlock() | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | 			return // The cache was reloaded recently. | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-10-09 12:40:50 +02:00
										 |  |  | 	// No watcher running, start it. | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | 	ac.watcher.start() | 
					
						
							|  |  |  | 	ac.throttle.Reset(minReloadInterval) | 
					
						
							| 
									
										
										
										
											2017-10-09 12:40:50 +02:00
										 |  |  | 	ac.mu.Unlock() | 
					
						
							|  |  |  | 	ac.scanAccounts() | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-02-07 12:47:34 +02:00
										 |  |  | func (ac *accountCache) close() { | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | 	ac.mu.Lock() | 
					
						
							|  |  |  | 	ac.watcher.close() | 
					
						
							|  |  |  | 	if ac.throttle != nil { | 
					
						
							|  |  |  | 		ac.throttle.Stop() | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-02-07 12:47:34 +02:00
										 |  |  | 	if ac.notify != nil { | 
					
						
							|  |  |  | 		close(ac.notify) | 
					
						
							|  |  |  | 		ac.notify = nil | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | 	ac.mu.Unlock() | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-10-09 12:40:50 +02:00
										 |  |  | // scanAccounts checks if any changes have occurred on the filesystem, and | 
					
						
							|  |  |  | // updates the account cache accordingly | 
					
						
							|  |  |  | func (ac *accountCache) scanAccounts() error { | 
					
						
							| 
									
										
										
										
											2017-11-20 12:21:52 +02:00
										 |  |  | 	// Scan the entire folder metadata for file changes | 
					
						
							|  |  |  | 	creates, deletes, updates, err := ac.fileC.scan(ac.keydir) | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | 	if err != nil { | 
					
						
							| 
									
										
										
										
											2017-10-09 12:40:50 +02:00
										 |  |  | 		log.Debug("Failed to reload keystore contents", "err", err) | 
					
						
							|  |  |  | 		return err | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-11-20 12:21:52 +02:00
										 |  |  | 	if creates.Size() == 0 && deletes.Size() == 0 && updates.Size() == 0 { | 
					
						
							|  |  |  | 		return nil | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	// Create a helper method to scan the contents of the key files | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | 	var ( | 
					
						
							| 
									
										
										
										
											2017-11-20 12:21:52 +02:00
										 |  |  | 		buf = new(bufio.Reader) | 
					
						
							|  |  |  | 		key struct { | 
					
						
							| 
									
										
										
										
											2016-11-28 01:30:54 +01:00
										 |  |  | 			Address string `json:"address"` | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	) | 
					
						
							| 
									
										
										
										
											2017-10-09 12:40:50 +02:00
										 |  |  | 	readAccount := func(path string) *accounts.Account { | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | 		fd, err := os.Open(path) | 
					
						
							|  |  |  | 		if err != nil { | 
					
						
							| 
									
										
										
										
											2017-10-09 12:40:50 +02:00
										 |  |  | 			log.Trace("Failed to open keystore file", "path", path, "err", err) | 
					
						
							|  |  |  | 			return nil | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-10-09 12:40:50 +02:00
										 |  |  | 		defer fd.Close() | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | 		buf.Reset(fd) | 
					
						
							|  |  |  | 		// Parse the address. | 
					
						
							| 
									
										
										
										
											2017-11-20 12:21:52 +02:00
										 |  |  | 		key.Address = "" | 
					
						
							|  |  |  | 		err = json.NewDecoder(buf).Decode(&key) | 
					
						
							|  |  |  | 		addr := common.HexToAddress(key.Address) | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | 		switch { | 
					
						
							|  |  |  | 		case err != nil: | 
					
						
							| 
									
										
										
										
											2017-10-09 12:40:50 +02:00
										 |  |  | 			log.Debug("Failed to decode keystore key", "path", path, "err", err) | 
					
						
							| 
									
										
										
										
											2016-11-28 01:30:54 +01:00
										 |  |  | 		case (addr == common.Address{}): | 
					
						
							| 
									
										
										
										
											2017-10-09 12:40:50 +02:00
										 |  |  | 			log.Debug("Failed to decode keystore key", "path", path, "err", "missing or zero address") | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | 		default: | 
					
						
							| 
									
										
										
										
											2017-10-09 12:40:50 +02:00
										 |  |  | 			return &accounts.Account{Address: addr, URL: accounts.URL{Scheme: KeyStoreScheme, Path: path}} | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | 		} | 
					
						
							| 
									
										
										
										
											2017-10-09 12:40:50 +02:00
										 |  |  | 		return nil | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-11-20 12:21:52 +02:00
										 |  |  | 	// Process all the file diffs | 
					
						
							|  |  |  | 	start := time.Now() | 
					
						
							| 
									
										
										
										
											2017-10-09 12:40:50 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2017-11-20 12:21:52 +02:00
										 |  |  | 	for _, p := range creates.List() { | 
					
						
							|  |  |  | 		if a := readAccount(p.(string)); a != nil { | 
					
						
							| 
									
										
										
										
											2017-10-09 12:40:50 +02:00
										 |  |  | 			ac.add(*a) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-11-20 12:21:52 +02:00
										 |  |  | 	for _, p := range deletes.List() { | 
					
						
							|  |  |  | 		ac.deleteByFile(p.(string)) | 
					
						
							| 
									
										
										
										
											2017-10-09 12:40:50 +02:00
										 |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-11-20 12:21:52 +02:00
										 |  |  | 	for _, p := range updates.List() { | 
					
						
							|  |  |  | 		path := p.(string) | 
					
						
							| 
									
										
										
										
											2017-10-09 12:40:50 +02:00
										 |  |  | 		ac.deleteByFile(path) | 
					
						
							| 
									
										
										
										
											2017-11-20 12:21:52 +02:00
										 |  |  | 		if a := readAccount(path); a != nil { | 
					
						
							| 
									
										
										
										
											2017-10-09 12:40:50 +02:00
										 |  |  | 			ac.add(*a) | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-11-20 12:21:52 +02:00
										 |  |  | 	end := time.Now() | 
					
						
							| 
									
										
										
										
											2017-10-09 12:40:50 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	select { | 
					
						
							|  |  |  | 	case ac.notify <- struct{}{}: | 
					
						
							|  |  |  | 	default: | 
					
						
							|  |  |  | 	} | 
					
						
							| 
									
										
										
										
											2017-11-20 12:21:52 +02:00
										 |  |  | 	log.Trace("Handled keystore changes", "time", end.Sub(start)) | 
					
						
							| 
									
										
										
										
											2017-10-09 12:40:50 +02:00
										 |  |  | 	return nil | 
					
						
							| 
									
										
										
										
											2016-03-03 01:15:42 +01:00
										 |  |  | } |