github.com/yinchengtsinghua/golang-Eos-dpos-Ethereum@v0.0.0-20190121132951-92cc4225ed8e/accounts/keystore/account_cache_test.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 "fmt" 29 "io/ioutil" 30 "math/rand" 31 "os" 32 "path/filepath" 33 "reflect" 34 "sort" 35 "testing" 36 "time" 37 38 "github.com/cespare/cp" 39 "github.com/davecgh/go-spew/spew" 40 "github.com/ethereum/go-ethereum/accounts" 41 "github.com/ethereum/go-ethereum/common" 42 ) 43 44 var ( 45 cachetestDir, _ = filepath.Abs(filepath.Join("testdata", "keystore")) 46 cachetestAccounts = []accounts.Account{ 47 { 48 Address: common.HexToAddress("7ef5a6135f1fd6a02593eedc869c6d41d934aef8"), 49 URL: accounts.URL{Scheme: KeyStoreScheme, Path: filepath.Join(cachetestDir, "UTC--2016-03-22T12-57-55.920751759Z--7ef5a6135f1fd6a02593eedc869c6d41d934aef8")}, 50 }, 51 { 52 Address: common.HexToAddress("f466859ead1932d743d622cb74fc058882e8648a"), 53 URL: accounts.URL{Scheme: KeyStoreScheme, Path: filepath.Join(cachetestDir, "aaa")}, 54 }, 55 { 56 Address: common.HexToAddress("289d485d9771714cce91d3393d764e1311907acc"), 57 URL: accounts.URL{Scheme: KeyStoreScheme, Path: filepath.Join(cachetestDir, "zzz")}, 58 }, 59 } 60 ) 61 62 func TestWatchNewFile(t *testing.T) { 63 t.Parallel() 64 65 dir, ks := tmpKeyStore(t, false) 66 defer os.RemoveAll(dir) 67 68 //在添加任何文件之前,请确保监视程序已启动。 69 ks.Accounts() 70 time.Sleep(1000 * time.Millisecond) 71 72 //移入文件。 73 wantAccounts := make([]accounts.Account, len(cachetestAccounts)) 74 for i := range cachetestAccounts { 75 wantAccounts[i] = accounts.Account{ 76 Address: cachetestAccounts[i].Address, 77 URL: accounts.URL{Scheme: KeyStoreScheme, Path: filepath.Join(dir, filepath.Base(cachetestAccounts[i].URL.Path))}, 78 } 79 if err := cp.CopyFile(wantAccounts[i].URL.Path, cachetestAccounts[i].URL.Path); err != nil { 80 t.Fatal(err) 81 } 82 } 83 84 //Ks应该看看账目。 85 var list []accounts.Account 86 for d := 200 * time.Millisecond; d < 5*time.Second; d *= 2 { 87 list = ks.Accounts() 88 if reflect.DeepEqual(list, wantAccounts) { 89 //KS也应该收到变更通知 90 select { 91 case <-ks.changes: 92 default: 93 t.Fatalf("wasn't notified of new accounts") 94 } 95 return 96 } 97 time.Sleep(d) 98 } 99 t.Errorf("got %s, want %s", spew.Sdump(list), spew.Sdump(wantAccounts)) 100 } 101 102 func TestWatchNoDir(t *testing.T) { 103 t.Parallel() 104 105 //创建ks,但不创建它监视的目录。 106 rand.Seed(time.Now().UnixNano()) 107 dir := filepath.Join(os.TempDir(), fmt.Sprintf("eth-keystore-watch-test-%d-%d", os.Getpid(), rand.Int())) 108 ks := NewKeyStore(dir, LightScryptN, LightScryptP) 109 110 list := ks.Accounts() 111 if len(list) > 0 { 112 t.Error("initial account list not empty:", list) 113 } 114 time.Sleep(100 * time.Millisecond) 115 116 //创建目录并将密钥文件复制到其中。 117 os.MkdirAll(dir, 0700) 118 defer os.RemoveAll(dir) 119 file := filepath.Join(dir, "aaa") 120 if err := cp.CopyFile(file, cachetestAccounts[0].URL.Path); err != nil { 121 t.Fatal(err) 122 } 123 124 //KS应该看到账户。 125 wantAccounts := []accounts.Account{cachetestAccounts[0]} 126 wantAccounts[0].URL = accounts.URL{Scheme: KeyStoreScheme, Path: file} 127 for d := 200 * time.Millisecond; d < 8*time.Second; d *= 2 { 128 list = ks.Accounts() 129 if reflect.DeepEqual(list, wantAccounts) { 130 //KS也应该收到变更通知 131 select { 132 case <-ks.changes: 133 default: 134 t.Fatalf("wasn't notified of new accounts") 135 } 136 return 137 } 138 time.Sleep(d) 139 } 140 t.Errorf("\ngot %v\nwant %v", list, wantAccounts) 141 } 142 143 func TestCacheInitialReload(t *testing.T) { 144 cache, _ := newAccountCache(cachetestDir) 145 accounts := cache.accounts() 146 if !reflect.DeepEqual(accounts, cachetestAccounts) { 147 t.Fatalf("got initial accounts: %swant %s", spew.Sdump(accounts), spew.Sdump(cachetestAccounts)) 148 } 149 } 150 151 func TestCacheAddDeleteOrder(t *testing.T) { 152 cache, _ := newAccountCache("testdata/no-such-dir") 153 cache.watcher.running = true //防止意外重新加载 154 155 accs := []accounts.Account{ 156 { 157 Address: common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87"), 158 URL: accounts.URL{Scheme: KeyStoreScheme, Path: "-309830980"}, 159 }, 160 { 161 Address: common.HexToAddress("2cac1adea150210703ba75ed097ddfe24e14f213"), 162 URL: accounts.URL{Scheme: KeyStoreScheme, Path: "ggg"}, 163 }, 164 { 165 Address: common.HexToAddress("8bda78331c916a08481428e4b07c96d3e916d165"), 166 URL: accounts.URL{Scheme: KeyStoreScheme, Path: "zzzzzz-the-very-last-one.keyXXX"}, 167 }, 168 { 169 Address: common.HexToAddress("d49ff4eeb0b2686ed89c0fc0f2b6ea533ddbbd5e"), 170 URL: accounts.URL{Scheme: KeyStoreScheme, Path: "SOMETHING.key"}, 171 }, 172 { 173 Address: common.HexToAddress("7ef5a6135f1fd6a02593eedc869c6d41d934aef8"), 174 URL: accounts.URL{Scheme: KeyStoreScheme, Path: "UTC--2016-03-22T12-57-55.920751759Z--7ef5a6135f1fd6a02593eedc869c6d41d934aef8"}, 175 }, 176 { 177 Address: common.HexToAddress("f466859ead1932d743d622cb74fc058882e8648a"), 178 URL: accounts.URL{Scheme: KeyStoreScheme, Path: "aaa"}, 179 }, 180 { 181 Address: common.HexToAddress("289d485d9771714cce91d3393d764e1311907acc"), 182 URL: accounts.URL{Scheme: KeyStoreScheme, Path: "zzz"}, 183 }, 184 } 185 for _, a := range accs { 186 cache.add(a) 187 } 188 //添加其中一些两次以检查它们是否没有重新插入。 189 cache.add(accs[0]) 190 cache.add(accs[2]) 191 192 //检查帐户列表是否按文件名排序。 193 wantAccounts := make([]accounts.Account, len(accs)) 194 copy(wantAccounts, accs) 195 sort.Sort(accountsByURL(wantAccounts)) 196 list := cache.accounts() 197 if !reflect.DeepEqual(list, wantAccounts) { 198 t.Fatalf("got accounts: %s\nwant %s", spew.Sdump(accs), spew.Sdump(wantAccounts)) 199 } 200 for _, a := range accs { 201 if !cache.hasAddress(a.Address) { 202 t.Errorf("expected hasAccount(%x) to return true", a.Address) 203 } 204 } 205 if cache.hasAddress(common.HexToAddress("fd9bd350f08ee3c0c19b85a8e16114a11a60aa4e")) { 206 t.Errorf("expected hasAccount(%x) to return false", common.HexToAddress("fd9bd350f08ee3c0c19b85a8e16114a11a60aa4e")) 207 } 208 209 //从缓存中删除一些键。 210 for i := 0; i < len(accs); i += 2 { 211 cache.delete(wantAccounts[i]) 212 } 213 cache.delete(accounts.Account{Address: common.HexToAddress("fd9bd350f08ee3c0c19b85a8e16114a11a60aa4e"), URL: accounts.URL{Scheme: KeyStoreScheme, Path: "something"}}) 214 215 //删除后再次检查内容。 216 wantAccountsAfterDelete := []accounts.Account{ 217 wantAccounts[1], 218 wantAccounts[3], 219 wantAccounts[5], 220 } 221 list = cache.accounts() 222 if !reflect.DeepEqual(list, wantAccountsAfterDelete) { 223 t.Fatalf("got accounts after delete: %s\nwant %s", spew.Sdump(list), spew.Sdump(wantAccountsAfterDelete)) 224 } 225 for _, a := range wantAccountsAfterDelete { 226 if !cache.hasAddress(a.Address) { 227 t.Errorf("expected hasAccount(%x) to return true", a.Address) 228 } 229 } 230 if cache.hasAddress(wantAccounts[0].Address) { 231 t.Errorf("expected hasAccount(%x) to return false", wantAccounts[0].Address) 232 } 233 } 234 235 func TestCacheFind(t *testing.T) { 236 dir := filepath.Join("testdata", "dir") 237 cache, _ := newAccountCache(dir) 238 cache.watcher.running = true //防止意外重新加载 239 240 accs := []accounts.Account{ 241 { 242 Address: common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87"), 243 URL: accounts.URL{Scheme: KeyStoreScheme, Path: filepath.Join(dir, "a.key")}, 244 }, 245 { 246 Address: common.HexToAddress("2cac1adea150210703ba75ed097ddfe24e14f213"), 247 URL: accounts.URL{Scheme: KeyStoreScheme, Path: filepath.Join(dir, "b.key")}, 248 }, 249 { 250 Address: common.HexToAddress("d49ff4eeb0b2686ed89c0fc0f2b6ea533ddbbd5e"), 251 URL: accounts.URL{Scheme: KeyStoreScheme, Path: filepath.Join(dir, "c.key")}, 252 }, 253 { 254 Address: common.HexToAddress("d49ff4eeb0b2686ed89c0fc0f2b6ea533ddbbd5e"), 255 URL: accounts.URL{Scheme: KeyStoreScheme, Path: filepath.Join(dir, "c2.key")}, 256 }, 257 } 258 for _, a := range accs { 259 cache.add(a) 260 } 261 262 nomatchAccount := accounts.Account{ 263 Address: common.HexToAddress("f466859ead1932d743d622cb74fc058882e8648a"), 264 URL: accounts.URL{Scheme: KeyStoreScheme, Path: filepath.Join(dir, "something")}, 265 } 266 tests := []struct { 267 Query accounts.Account 268 WantResult accounts.Account 269 WantError error 270 }{ 271 //按地址 272 {Query: accounts.Account{Address: accs[0].Address}, WantResult: accs[0]}, 273 //按文件 274 {Query: accounts.Account{URL: accs[0].URL}, WantResult: accs[0]}, 275 //用BaseNeMe 276 {Query: accounts.Account{URL: accounts.URL{Scheme: KeyStoreScheme, Path: filepath.Base(accs[0].URL.Path)}}, WantResult: accs[0]}, 277 //按文件和地址 278 {Query: accs[0], WantResult: accs[0]}, 279 //地址不明确,由文件解析的领带 280 {Query: accs[2], WantResult: accs[2]}, 281 //地址不明确错误 282 { 283 Query: accounts.Account{Address: accs[2].Address}, 284 WantError: &AmbiguousAddrError{ 285 Addr: accs[2].Address, 286 Matches: []accounts.Account{accs[2], accs[3]}, 287 }, 288 }, 289 //无匹配误差 290 {Query: nomatchAccount, WantError: ErrNoMatch}, 291 {Query: accounts.Account{URL: nomatchAccount.URL}, WantError: ErrNoMatch}, 292 {Query: accounts.Account{URL: accounts.URL{Scheme: KeyStoreScheme, Path: filepath.Base(nomatchAccount.URL.Path)}}, WantError: ErrNoMatch}, 293 {Query: accounts.Account{Address: nomatchAccount.Address}, WantError: ErrNoMatch}, 294 } 295 for i, test := range tests { 296 a, err := cache.find(test.Query) 297 if !reflect.DeepEqual(err, test.WantError) { 298 t.Errorf("test %d: error mismatch for query %v\ngot %q\nwant %q", i, test.Query, err, test.WantError) 299 continue 300 } 301 if a != test.WantResult { 302 t.Errorf("test %d: result mismatch for query %v\ngot %v\nwant %v", i, test.Query, a, test.WantResult) 303 continue 304 } 305 } 306 } 307 308 func waitForAccounts(wantAccounts []accounts.Account, ks *KeyStore) error { 309 var list []accounts.Account 310 for d := 200 * time.Millisecond; d < 8*time.Second; d *= 2 { 311 list = ks.Accounts() 312 if reflect.DeepEqual(list, wantAccounts) { 313 //KS也应该收到变更通知 314 select { 315 case <-ks.changes: 316 default: 317 return fmt.Errorf("wasn't notified of new accounts") 318 } 319 return nil 320 } 321 time.Sleep(d) 322 } 323 return fmt.Errorf("\ngot %v\nwant %v", list, wantAccounts) 324 } 325 326 //testUpdatedKeyFileContents测试更新密钥库文件的内容 327 //被观察者注意到,帐户缓存会相应地更新 328 func TestUpdatedKeyfileContents(t *testing.T) { 329 t.Parallel() 330 331 //创建要测试的临时Kesytore 332 rand.Seed(time.Now().UnixNano()) 333 dir := filepath.Join(os.TempDir(), fmt.Sprintf("eth-keystore-watch-test-%d-%d", os.Getpid(), rand.Int())) 334 ks := NewKeyStore(dir, LightScryptN, LightScryptP) 335 336 list := ks.Accounts() 337 if len(list) > 0 { 338 t.Error("initial account list not empty:", list) 339 } 340 time.Sleep(100 * time.Millisecond) 341 342 //创建目录并将密钥文件复制到其中。 343 os.MkdirAll(dir, 0700) 344 defer os.RemoveAll(dir) 345 file := filepath.Join(dir, "aaa") 346 347 //把我们的一个测试文件放在那里 348 if err := cp.CopyFile(file, cachetestAccounts[0].URL.Path); err != nil { 349 t.Fatal(err) 350 } 351 352 //KS应该看到账户。 353 wantAccounts := []accounts.Account{cachetestAccounts[0]} 354 wantAccounts[0].URL = accounts.URL{Scheme: KeyStoreScheme, Path: file} 355 if err := waitForAccounts(wantAccounts, ks); err != nil { 356 t.Error(err) 357 return 358 } 359 360 //需要,以便“file”的modtime与forcecopyfile之后的当前值不同 361 time.Sleep(1000 * time.Millisecond) 362 363 //现在替换文件内容 364 if err := forceCopyFile(file, cachetestAccounts[1].URL.Path); err != nil { 365 t.Fatal(err) 366 return 367 } 368 wantAccounts = []accounts.Account{cachetestAccounts[1]} 369 wantAccounts[0].URL = accounts.URL{Scheme: KeyStoreScheme, Path: file} 370 if err := waitForAccounts(wantAccounts, ks); err != nil { 371 t.Errorf("First replacement failed") 372 t.Error(err) 373 return 374 } 375 376 //需要,以便“file”的modtime与forcecopyfile之后的当前值不同 377 time.Sleep(1000 * time.Millisecond) 378 379 //现在重新替换文件内容 380 if err := forceCopyFile(file, cachetestAccounts[2].URL.Path); err != nil { 381 t.Fatal(err) 382 return 383 } 384 wantAccounts = []accounts.Account{cachetestAccounts[2]} 385 wantAccounts[0].URL = accounts.URL{Scheme: KeyStoreScheme, Path: file} 386 if err := waitForAccounts(wantAccounts, ks); err != nil { 387 t.Errorf("Second replacement failed") 388 t.Error(err) 389 return 390 } 391 392 //需要,以便“file”的modtime与ioutil.writefile之后的当前值不同 393 time.Sleep(1000 * time.Millisecond) 394 395 //现在用垃圾替换文件内容 396 if err := ioutil.WriteFile(file, []byte("foo"), 0644); err != nil { 397 t.Fatal(err) 398 return 399 } 400 if err := waitForAccounts([]accounts.Account{}, ks); err != nil { 401 t.Errorf("Emptying account file failed") 402 t.Error(err) 403 return 404 } 405 } 406 407 //forcecopyfile与cp.copyfile类似,但如果目标存在,则不会抱怨。 408 func forceCopyFile(dst, src string) error { 409 data, err := ioutil.ReadFile(src) 410 if err != nil { 411 return err 412 } 413 return ioutil.WriteFile(dst, data, 0644) 414 }