github.com/ethereumproject/go-ethereum@v5.5.2+incompatible/accounts/cachedb_test.go (about)

     1  package accounts
     2  
     3  import (
     4  	"io/ioutil"
     5  	"os"
     6  	"path/filepath"
     7  	"reflect"
     8  	"sort"
     9  	"testing"
    10  	"time"
    11  
    12  	"github.com/davecgh/go-spew/spew"
    13  	"github.com/ethereumproject/go-ethereum/common"
    14  )
    15  
    16  var (
    17  	cachedbtestAccounts = []Account{
    18  		{
    19  			Address:      common.HexToAddress("7ef5a6135f1fd6a02593eedc869c6d41d934aef8"),
    20  			File:         "UTC--2016-03-22T12-57-55.920751759Z--7ef5a6135f1fd6a02593eedc869c6d41d934aef8",
    21  			EncryptedKey: "{\"address\":\"7ef5a6135f1fd6a02593eedc869c6d41d934aef8\",\"crypto\":{\"cipher\":\"aes-128-ctr\",\"ciphertext\":\"1d0839166e7a15b9c1333fc865d69858b22df26815ccf601b28219b6192974e1\",\"cipherparams\":{\"iv\":\"8df6caa7ff1b00c4e871f002cb7921ed\"},\"kdf\":\"scrypt\",\"kdfparams\":{\"dklen\":32,\"n\":8,\"p\":16,\"r\":8,\"salt\":\"e5e6ef3f4ea695f496b643ebd3f75c0aa58ef4070e90c80c5d3fb0241bf1595c\"},\"mac\":\"6d16dfde774845e4585357f24bce530528bc69f4f84e1e22880d34fa45c273e5\"},\"id\":\"950077c7-71e3-4c44-a4a1-143919141ed4\",\"version\":3}",
    22  		},
    23  		{
    24  			Address:      common.HexToAddress("f466859ead1932d743d622cb74fc058882e8648a"),
    25  			File:         "aaa",
    26  			EncryptedKey: "{\"address\":\"f466859ead1932d743d622cb74fc058882e8648a\",\"crypto\":{\"cipher\":\"aes-128-ctr\",\"ciphertext\":\"cb664472deacb41a2e995fa7f96fe29ce744471deb8d146a0e43c7898c9ddd4d\",\"cipherparams\":{\"iv\":\"dfd9ee70812add5f4b8f89d0811c9158\"},\"kdf\":\"scrypt\",\"kdfparams\":{\"dklen\":32,\"n\":8,\"p\":16,\"r\":8,\"salt\":\"0d6769bf016d45c479213990d6a08d938469c4adad8a02ce507b4a4e7b7739f1\"},\"mac\":\"bac9af994b15a45dd39669fc66f9aa8a3b9dd8c22cb16e4d8d7ea089d0f1a1a9\"},\"id\":\"472e8b3d-afb6-45b5-8111-72c89895099a\",\"version\":3}",
    27  		},
    28  		{
    29  			Address:      common.HexToAddress("289d485d9771714cce91d3393d764e1311907acc"),
    30  			File:         "zzz",
    31  			EncryptedKey: "{\"address\":\"289d485d9771714cce91d3393d764e1311907acc\",\"crypto\":{\"cipher\":\"aes-128-ctr\",\"ciphertext\":\"faf32ca89d286b107f5e6d842802e05263c49b78d46eac74e6109e9a963378ab\",\"cipherparams\":{\"iv\":\"558833eec4a665a8c55608d7d503407d\"},\"kdf\":\"scrypt\",\"kdfparams\":{\"dklen\":32,\"n\":8,\"p\":16,\"r\":8,\"salt\":\"d571fff447ffb24314f9513f5160246f09997b857ac71348b73e785aab40dc04\"},\"mac\":\"21edb85ff7d0dab1767b9bf498f2c3cb7be7609490756bd32300bb213b59effe\"},\"id\":\"3279afcf-55ba-43ff-8997-02dcc46a6525\",\"version\":3}",
    32  		},
    33  	}
    34  )
    35  
    36  func TestCacheInitialReload_CacheDB(t *testing.T) {
    37  	cache := newCacheDB(cachetestDir)
    38  	cache.Syncfs2db(time.Now())
    39  	defer cache.close()
    40  
    41  	accounts := cache.accounts()
    42  
    43  	if !reflect.DeepEqual(accounts, cachedbtestAccounts) {
    44  		t.Errorf("got: %v, want %v", spew.Sdump(accounts), spew.Sdump(cachedbtestAccounts))
    45  	}
    46  }
    47  
    48  func TestCacheAddDeleteOrder_CacheDB(t *testing.T) {
    49  	cache := newCacheDB("testdata/no-such-dir")
    50  	defer cache.close()
    51  	defer os.RemoveAll("testdata/no-such-dir")
    52  
    53  	accounts := []Account{
    54  		{
    55  			Address: common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87"),
    56  			File:    "-309830980",
    57  		},
    58  		{
    59  			Address: common.HexToAddress("2cac1adea150210703ba75ed097ddfe24e14f213"),
    60  			File:    "ggg",
    61  		},
    62  		{
    63  			Address: common.HexToAddress("8bda78331c916a08481428e4b07c96d3e916d165"),
    64  			File:    "zzzzzz-the-very-last-one.keyXXX",
    65  		},
    66  		{
    67  			Address: common.HexToAddress("d49ff4eeb0b2686ed89c0fc0f2b6ea533ddbbd5e"),
    68  			File:    "SOMETHING.key",
    69  		},
    70  		{
    71  			Address: common.HexToAddress("7ef5a6135f1fd6a02593eedc869c6d41d934aef8"),
    72  			File:    "UTC--2016-03-22T12-57-55.920751759Z--7ef5a6135f1fd6a02593eedc869c6d41d934aef8",
    73  		},
    74  		{
    75  			Address: common.HexToAddress("f466859ead1932d743d622cb74fc058882e8648a"),
    76  			File:    "aaa",
    77  		},
    78  		{
    79  			Address: common.HexToAddress("289d485d9771714cce91d3393d764e1311907acc"),
    80  			File:    "zzz",
    81  		},
    82  	}
    83  	for _, a := range accounts {
    84  		cache.add(a)
    85  	}
    86  	// Add some of them twice to check that they don't get reinserted.
    87  	cache.add(accounts[0])
    88  	cache.add(accounts[2])
    89  
    90  	// Check that the account list is sorted by filename.
    91  	wantAccounts := make([]Account, len(accounts))
    92  	copy(wantAccounts, accounts)
    93  	sort.Sort(accountsByFile(wantAccounts))
    94  	list := cache.accounts()
    95  	if !reflect.DeepEqual(list, wantAccounts) {
    96  		t.Fatalf("got accounts: %s\nwant %s", spew.Sdump(accounts), spew.Sdump(wantAccounts))
    97  	}
    98  	for _, a := range accounts {
    99  		if !cache.hasAddress(a.Address) {
   100  			t.Errorf("expected hasAccount(%x) to return true", a.Address)
   101  		}
   102  	}
   103  	if cache.hasAddress(common.HexToAddress("fd9bd350f08ee3c0c19b85a8e16114a11a60aa4e")) {
   104  		t.Errorf("expected hasAccount(%x) to return false", common.HexToAddress("fd9bd350f08ee3c0c19b85a8e16114a11a60aa4e"))
   105  	}
   106  
   107  	// Delete a few keys from the cache.
   108  	for i := 0; i < len(accounts); i += 2 {
   109  		cache.delete(wantAccounts[i])
   110  	}
   111  	cache.delete(Account{Address: common.HexToAddress("fd9bd350f08ee3c0c19b85a8e16114a11a60aa4e"), File: "something"})
   112  
   113  	// Check content again after deletion.
   114  	wantAccountsAfterDelete := []Account{
   115  		wantAccounts[1],
   116  		wantAccounts[3],
   117  		wantAccounts[5],
   118  	}
   119  	list = cache.accounts()
   120  	if !reflect.DeepEqual(list, wantAccountsAfterDelete) {
   121  		t.Fatalf("got accounts after delete: %s\nwant %s", spew.Sdump(list), spew.Sdump(wantAccountsAfterDelete))
   122  	}
   123  	for _, a := range wantAccountsAfterDelete {
   124  		if !cache.hasAddress(a.Address) {
   125  			t.Errorf("expected hasAccount(%x) to return true", a.Address)
   126  		}
   127  	}
   128  	if cache.hasAddress(wantAccounts[0].Address) {
   129  		t.Errorf("expected hasAccount(%x) to return false", wantAccounts[0].Address)
   130  	}
   131  }
   132  
   133  func TestCacheFind_CacheFind(t *testing.T) {
   134  	dir := filepath.Join("testdata", "dir")
   135  	cache := newCacheDB(dir)
   136  	defer cache.close()
   137  	defer os.RemoveAll(dir)
   138  
   139  	accounts := []Account{
   140  		{
   141  			Address: common.HexToAddress("095e7baea6a6c7c4c2dfeb977efac326af552d87"),
   142  			File:    "a.key",
   143  		},
   144  		{
   145  			Address: common.HexToAddress("2cac1adea150210703ba75ed097ddfe24e14f213"),
   146  			File:    "b.key",
   147  		},
   148  		{
   149  			Address: common.HexToAddress("d49ff4eeb0b2686ed89c0fc0f2b6ea533ddbbd5e"),
   150  			File:    "c.key",
   151  		},
   152  		{
   153  			Address: common.HexToAddress("d49ff4eeb0b2686ed89c0fc0f2b6ea533ddbbd5e"),
   154  			File:    "c2.key",
   155  		},
   156  	}
   157  	for _, a := range accounts {
   158  		cache.add(a)
   159  	}
   160  
   161  	if lca := cache.accounts(); len(lca) != len(accounts) {
   162  		t.Fatalf("wrong number of accounts, got: %v, want: %v", len(lca), len(accounts))
   163  	}
   164  
   165  	if !reflect.DeepEqual(cache.accounts(), accounts) {
   166  		t.Fatalf("not matching initial accounts: got %v, want: %v", spew.Sdump(cache.accounts()), spew.Sdump(accounts))
   167  	}
   168  
   169  	nomatchAccount := Account{
   170  		Address: common.HexToAddress("f466859ead1932d743d622cb74fc058882e8648a"),
   171  		File:    filepath.Join(dir, "something"),
   172  	}
   173  	tests := []struct {
   174  		Query      Account
   175  		WantResult Account
   176  		WantError  error
   177  	}{
   178  		// by address
   179  		{Query: Account{Address: accounts[0].Address}, WantResult: accounts[0]},
   180  		// by file
   181  		{Query: Account{File: accounts[0].File}, WantResult: accounts[0]},
   182  		// by basename
   183  		{Query: Account{File: filepath.Base(accounts[0].File)}, WantResult: accounts[0]},
   184  		// by file and address
   185  		{Query: accounts[0], WantResult: accounts[0]},
   186  		// ambiguous address, tie resolved by file
   187  		{Query: accounts[2], WantResult: accounts[2]},
   188  		// ambiguous address error
   189  		{
   190  			Query: Account{Address: accounts[2].Address},
   191  			WantError: &AmbiguousAddrError{
   192  				Addr:    accounts[2].Address,
   193  				Matches: []Account{accounts[2], accounts[3]},
   194  			},
   195  		},
   196  		// no match error
   197  		{Query: nomatchAccount, WantError: ErrNoMatch},
   198  		{Query: Account{File: nomatchAccount.File}, WantError: ErrNoMatch},
   199  		{Query: Account{File: filepath.Base(nomatchAccount.File)}, WantError: ErrNoMatch},
   200  		{Query: Account{Address: nomatchAccount.Address}, WantError: ErrNoMatch},
   201  	}
   202  	for i, test := range tests {
   203  		a, err := cache.find(test.Query)
   204  		if !reflect.DeepEqual(err, test.WantError) {
   205  			t.Errorf("test %d: error mismatch for query %v\ngot %q\nwant %q", i, test.Query, err, test.WantError)
   206  			continue
   207  		}
   208  		if a != test.WantResult {
   209  			t.Errorf("test %d: result mismatch for query %v\ngot %v\nwant %v", i, test.Query, a, test.WantResult)
   210  			continue
   211  		}
   212  	}
   213  }
   214  
   215  func TestAccountCache_CacheDB_SyncFS2DB(t *testing.T) {
   216  	// setup temp dir
   217  	tmpDir, e := ioutil.TempDir("", "cachedb-remover-test")
   218  	if e != nil {
   219  		t.Fatalf("create temp dir: %v", e)
   220  	}
   221  	defer os.RemoveAll(tmpDir)
   222  
   223  	// make manager in temp dir
   224  	ma, e := NewManager(tmpDir, veryLightScryptN, veryLightScryptP, true)
   225  	if e != nil {
   226  		t.Errorf("create manager in temp dir: %v", e)
   227  	}
   228  	// test manager has no accounts
   229  	initAccs := ma.Accounts()
   230  	if !reflect.DeepEqual(initAccs, []Account{}) {
   231  		t.Errorf("got %v, want: %v", spew.Sdump(initAccs), spew.Sdump([]Account{}))
   232  	}
   233  	// close manager
   234  	ma.ac.close()
   235  	ma = nil
   236  
   237  	// copy 3 key files to temp dir
   238  	for _, acc := range cachedbtestAccounts {
   239  		data, err := ioutil.ReadFile(filepath.Join(cachetestDir, acc.File))
   240  		if err != nil {
   241  			t.Fatal(err)
   242  		}
   243  		ff, err := os.Create(filepath.Join(tmpDir, acc.File))
   244  		if err != nil {
   245  			t.Fatal(err)
   246  		}
   247  		_, err = ff.Write(data)
   248  		if err != nil {
   249  			t.Fatal(err)
   250  		}
   251  		ff.Close()
   252  	}
   253  
   254  	// restart manager in temp dir
   255  	ma, e = NewManager(tmpDir, veryLightScryptN, veryLightScryptP, true)
   256  	if e != nil {
   257  		t.Errorf("create manager in temp dir: %v", e)
   258  	}
   259  
   260  	ma.ac.Syncfs2db(time.Now())
   261  
   262  	// test manager has 3 accounts
   263  	initAccs = ma.Accounts()
   264  	if !reflect.DeepEqual(initAccs, cachedbtestAccounts) {
   265  		t.Errorf("got %v, want: %v", spew.Sdump(initAccs), spew.Sdump(cachedbtestAccounts))
   266  	}
   267  
   268  	// close manager
   269  	ma.ac.close()
   270  	ma = nil
   271  
   272  	// remove 1 key file from temp dir
   273  	rmPath := filepath.Join(tmpDir, cachedbtestAccounts[0].File)
   274  	if e := os.Remove(rmPath); e != nil {
   275  		t.Fatalf("removing key file: %v", e)
   276  	}
   277  
   278  	// restart manager in temp dir
   279  	ma, e = NewManager(tmpDir, veryLightScryptN, veryLightScryptP, true)
   280  	if e != nil {
   281  		t.Errorf("create manager in temp dir: %v", e)
   282  	}
   283  	ma.ac.Syncfs2db(time.Now())
   284  
   285  	// test manager has 2 accounts
   286  	initAccs = ma.Accounts()
   287  	if !reflect.DeepEqual(initAccs, cachedbtestAccounts[1:]) {
   288  		t.Errorf("got %v, want: %v", spew.Sdump(initAccs), spew.Sdump(cachedbtestAccounts[1:]))
   289  	}
   290  	ma.ac.close()
   291  }
   292  
   293  func TestCacheDBFilePath(t *testing.T) {
   294  	dir := filepath.Join("testdata", "keystore")
   295  	dir, _ = filepath.Abs(dir)
   296  	cache := newCacheDB(dir)
   297  	defer cache.close()
   298  
   299  	accs := cache.accounts()
   300  
   301  	for _, a := range accs {
   302  		if filepath.IsAbs(a.File) {
   303  			t.Errorf("wanted relative filepath (wanted basename), got: %v", a.File)
   304  		}
   305  	}
   306  }