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