github.com/linapex/ethereum-dpos-chinese@v0.0.0-20190316121959-b78b3a4a1ece/accounts/keystore/account_cache.go (about) 1 2 //<developer> 3 // <name>linapex 曹一峰</name> 4 // <email>linapex@163.com</email> 5 // <wx>superexc</wx> 6 // <qqgroup>128148617</qqgroup> 7 // <url>https://jsq.ink</url> 8 // <role>pku engineer</role> 9 // <date>2019-03-16 12:09:26</date> 10 //</624342584738713600> 11 12 13 package keystore 14 15 import ( 16 "bufio" 17 "encoding/json" 18 "fmt" 19 "os" 20 "path/filepath" 21 "sort" 22 "strings" 23 "sync" 24 "time" 25 26 mapset "github.com/deckarep/golang-set" 27 "github.com/ethereum/go-ethereum/accounts" 28 "github.com/ethereum/go-ethereum/common" 29 "github.com/ethereum/go-ethereum/log" 30 ) 31 32 //缓存重新加载之间的最短时间间隔。此限制适用于平台 33 //不支持更改通知。如果keystore目录没有 34 //尽管存在,代码最多也会尝试创建一个观察程序。 35 const minReloadInterval = 2 * time.Second 36 37 type accountsByURL []accounts.Account 38 39 func (s accountsByURL) Len() int { return len(s) } 40 func (s accountsByURL) Less(i, j int) bool { return s[i].URL.Cmp(s[j].URL) < 0 } 41 func (s accountsByURL) Swap(i, j int) { s[i], s[j] = s[j], s[i] } 42 43 //尝试解锁时返回ambiguousaddrror 44 //存在多个文件的地址。 45 type AmbiguousAddrError struct { 46 Addr common.Address 47 Matches []accounts.Account 48 } 49 50 func (err *AmbiguousAddrError) Error() string { 51 files := "" 52 for i, a := range err.Matches { 53 files += a.URL.Path 54 if i < len(err.Matches)-1 { 55 files += ", " 56 } 57 } 58 return fmt.Sprintf("multiple keys match address (%s)", files) 59 } 60 61 //accountcache是密钥库中所有帐户的实时索引。 62 type accountCache struct { 63 keydir string 64 watcher *watcher 65 mu sync.Mutex 66 all accountsByURL 67 byAddr map[common.Address][]accounts.Account 68 throttle *time.Timer 69 notify chan struct{} 70 fileC fileCache 71 } 72 73 func newAccountCache(keydir string) (*accountCache, chan struct{}) { 74 ac := &accountCache{ 75 keydir: keydir, 76 byAddr: make(map[common.Address][]accounts.Account), 77 notify: make(chan struct{}, 1), 78 fileC: fileCache{all: mapset.NewThreadUnsafeSet()}, 79 } 80 ac.watcher = newWatcher(ac) 81 return ac, ac.notify 82 } 83 84 func (ac *accountCache) accounts() []accounts.Account { 85 ac.maybeReload() 86 ac.mu.Lock() 87 defer ac.mu.Unlock() 88 cpy := make([]accounts.Account, len(ac.all)) 89 copy(cpy, ac.all) 90 return cpy 91 } 92 93 func (ac *accountCache) hasAddress(addr common.Address) bool { 94 ac.maybeReload() 95 ac.mu.Lock() 96 defer ac.mu.Unlock() 97 return len(ac.byAddr[addr]) > 0 98 } 99 100 func (ac *accountCache) add(newAccount accounts.Account) { 101 ac.mu.Lock() 102 defer ac.mu.Unlock() 103 104 i := sort.Search(len(ac.all), func(i int) bool { return ac.all[i].URL.Cmp(newAccount.URL) >= 0 }) 105 if i < len(ac.all) && ac.all[i] == newAccount { 106 return 107 } 108 //NewAccount不在缓存中。 109 ac.all = append(ac.all, accounts.Account{}) 110 copy(ac.all[i+1:], ac.all[i:]) 111 ac.all[i] = newAccount 112 ac.byAddr[newAccount.Address] = append(ac.byAddr[newAccount.Address], newAccount) 113 } 114 115 //注意:删除的文件必须是唯一的(即必须同时设置文件和地址)。 116 func (ac *accountCache) delete(removed accounts.Account) { 117 ac.mu.Lock() 118 defer ac.mu.Unlock() 119 120 ac.all = removeAccount(ac.all, removed) 121 if ba := removeAccount(ac.byAddr[removed.Address], removed); len(ba) == 0 { 122 delete(ac.byAddr, removed.Address) 123 } else { 124 ac.byAddr[removed.Address] = ba 125 } 126 } 127 128 //DeleteByFile删除由给定路径引用的帐户。 129 func (ac *accountCache) deleteByFile(path string) { 130 ac.mu.Lock() 131 defer ac.mu.Unlock() 132 i := sort.Search(len(ac.all), func(i int) bool { return ac.all[i].URL.Path >= path }) 133 134 if i < len(ac.all) && ac.all[i].URL.Path == path { 135 removed := ac.all[i] 136 ac.all = append(ac.all[:i], ac.all[i+1:]...) 137 if ba := removeAccount(ac.byAddr[removed.Address], removed); len(ba) == 0 { 138 delete(ac.byAddr, removed.Address) 139 } else { 140 ac.byAddr[removed.Address] = ba 141 } 142 } 143 } 144 145 func removeAccount(slice []accounts.Account, elem accounts.Account) []accounts.Account { 146 for i := range slice { 147 if slice[i] == elem { 148 return append(slice[:i], slice[i+1:]...) 149 } 150 } 151 return slice 152 } 153 154 //如果存在唯一匹配项,find返回地址的缓存帐户。 155 //accounts.account的文档解释了精确的匹配规则。 156 //呼叫者必须持有AC.MU。 157 func (ac *accountCache) find(a accounts.Account) (accounts.Account, error) { 158 //如果可能的话,限制搜索以满足候选人的要求。 159 matches := ac.all 160 if (a.Address != common.Address{}) { 161 matches = ac.byAddr[a.Address] 162 } 163 if a.URL.Path != "" { 164 //如果只指定了basename,请完成路径。 165 if !strings.ContainsRune(a.URL.Path, filepath.Separator) { 166 a.URL.Path = filepath.Join(ac.keydir, a.URL.Path) 167 } 168 for i := range matches { 169 if matches[i].URL == a.URL { 170 return matches[i], nil 171 } 172 } 173 if (a.Address == common.Address{}) { 174 return accounts.Account{}, ErrNoMatch 175 } 176 } 177 switch len(matches) { 178 case 1: 179 return matches[0], nil 180 case 0: 181 return accounts.Account{}, ErrNoMatch 182 default: 183 err := &AmbiguousAddrError{Addr: a.Address, Matches: make([]accounts.Account, len(matches))} 184 copy(err.Matches, matches) 185 sort.Sort(accountsByURL(err.Matches)) 186 return accounts.Account{}, err 187 } 188 } 189 190 func (ac *accountCache) maybeReload() { 191 ac.mu.Lock() 192 193 if ac.watcher.running { 194 ac.mu.Unlock() 195 return //观察程序正在运行并将保持缓存的最新状态。 196 } 197 if ac.throttle == nil { 198 ac.throttle = time.NewTimer(0) 199 } else { 200 select { 201 case <-ac.throttle.C: 202 default: 203 ac.mu.Unlock() 204 return //缓存最近被重新加载。 205 } 206 } 207 //没有观察者在运行,启动它。 208 ac.watcher.start() 209 ac.throttle.Reset(minReloadInterval) 210 ac.mu.Unlock() 211 ac.scanAccounts() 212 } 213 214 func (ac *accountCache) close() { 215 ac.mu.Lock() 216 ac.watcher.close() 217 if ac.throttle != nil { 218 ac.throttle.Stop() 219 } 220 if ac.notify != nil { 221 close(ac.notify) 222 ac.notify = nil 223 } 224 ac.mu.Unlock() 225 } 226 227 //scanaccounts检查文件系统是否发生任何更改,以及 228 //相应地更新帐户缓存 229 func (ac *accountCache) scanAccounts() error { 230 //扫描整个文件夹元数据以查找文件更改 231 creates, deletes, updates, err := ac.fileC.scan(ac.keydir) 232 if err != nil { 233 log.Debug("Failed to reload keystore contents", "err", err) 234 return err 235 } 236 if creates.Cardinality() == 0 && deletes.Cardinality() == 0 && updates.Cardinality() == 0 { 237 return nil 238 } 239 //创建一个助手方法来扫描密钥文件的内容 240 var ( 241 buf = new(bufio.Reader) 242 key struct { 243 Address string `json:"address"` 244 } 245 ) 246 readAccount := func(path string) *accounts.Account { 247 fd, err := os.Open(path) 248 if err != nil { 249 log.Trace("Failed to open keystore file", "path", path, "err", err) 250 return nil 251 } 252 defer fd.Close() 253 buf.Reset(fd) 254 //分析地址。 255 key.Address = "" 256 err = json.NewDecoder(buf).Decode(&key) 257 addr := common.HexToAddress(key.Address) 258 switch { 259 case err != nil: 260 log.Debug("Failed to decode keystore key", "path", path, "err", err) 261 case (addr == common.Address{}): 262 log.Debug("Failed to decode keystore key", "path", path, "err", "missing or zero address") 263 default: 264 return &accounts.Account{Address: addr, URL: accounts.URL{Scheme: KeyStoreScheme, Path: path}} 265 } 266 return nil 267 } 268 //处理所有文件差异 269 start := time.Now() 270 271 for _, p := range creates.ToSlice() { 272 if a := readAccount(p.(string)); a != nil { 273 ac.add(*a) 274 } 275 } 276 for _, p := range deletes.ToSlice() { 277 ac.deleteByFile(p.(string)) 278 } 279 for _, p := range updates.ToSlice() { 280 path := p.(string) 281 ac.deleteByFile(path) 282 if a := readAccount(path); a != nil { 283 ac.add(*a) 284 } 285 } 286 end := time.Now() 287 288 select { 289 case ac.notify <- struct{}{}: 290 default: 291 } 292 log.Trace("Handled keystore changes", "time", end.Sub(start)) 293 return nil 294 } 295