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  }