keystore_test.go 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474
  1. // Copyright 2017 The go-ethereum Authors
  2. // This file is part of the go-ethereum library.
  3. //
  4. // The go-ethereum library is free software: you can redistribute it and/or modify
  5. // it under the terms of the GNU Lesser General Public License as published by
  6. // the Free Software Foundation, either version 3 of the License, or
  7. // (at your option) any later version.
  8. //
  9. // The go-ethereum library is distributed in the hope that it will be useful,
  10. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. // GNU Lesser General Public License for more details.
  13. //
  14. // You should have received a copy of the GNU Lesser General Public License
  15. // along with the go-ethereum library. If not, see <http://www.gnu.org/licenses/>.
  16. package keystore
  17. import (
  18. "io/ioutil"
  19. "math/rand"
  20. "os"
  21. "runtime"
  22. "sort"
  23. "strings"
  24. "sync"
  25. "sync/atomic"
  26. "testing"
  27. "time"
  28. "github.com/ethereum/go-ethereum/accounts"
  29. "github.com/ethereum/go-ethereum/common"
  30. "github.com/ethereum/go-ethereum/crypto"
  31. "github.com/ethereum/go-ethereum/event"
  32. )
  33. var testSigData = make([]byte, 32)
  34. func TestKeyStore(t *testing.T) {
  35. dir, ks := tmpKeyStore(t, true)
  36. defer os.RemoveAll(dir)
  37. a, err := ks.NewAccount("foo")
  38. if err != nil {
  39. t.Fatal(err)
  40. }
  41. if !strings.HasPrefix(a.URL.Path, dir) {
  42. t.Errorf("account file %s doesn't have dir prefix", a.URL)
  43. }
  44. stat, err := os.Stat(a.URL.Path)
  45. if err != nil {
  46. t.Fatalf("account file %s doesn't exist (%v)", a.URL, err)
  47. }
  48. if runtime.GOOS != "windows" && stat.Mode() != 0600 {
  49. t.Fatalf("account file has wrong mode: got %o, want %o", stat.Mode(), 0600)
  50. }
  51. if !ks.HasAddress(a.Address) {
  52. t.Errorf("HasAccount(%x) should've returned true", a.Address)
  53. }
  54. if err := ks.Update(a, "foo", "bar"); err != nil {
  55. t.Errorf("Update error: %v", err)
  56. }
  57. if err := ks.Delete(a, "bar"); err != nil {
  58. t.Errorf("Delete error: %v", err)
  59. }
  60. if common.FileExist(a.URL.Path) {
  61. t.Errorf("account file %s should be gone after Delete", a.URL)
  62. }
  63. if ks.HasAddress(a.Address) {
  64. t.Errorf("HasAccount(%x) should've returned true after Delete", a.Address)
  65. }
  66. }
  67. func TestSign(t *testing.T) {
  68. dir, ks := tmpKeyStore(t, true)
  69. defer os.RemoveAll(dir)
  70. pass := "" // not used but required by API
  71. a1, err := ks.NewAccount(pass)
  72. if err != nil {
  73. t.Fatal(err)
  74. }
  75. if err := ks.Unlock(a1, ""); err != nil {
  76. t.Fatal(err)
  77. }
  78. if _, err := ks.SignHash(accounts.Account{Address: a1.Address}, testSigData); err != nil {
  79. t.Fatal(err)
  80. }
  81. }
  82. func TestSignWithPassphrase(t *testing.T) {
  83. dir, ks := tmpKeyStore(t, true)
  84. defer os.RemoveAll(dir)
  85. pass := "passwd"
  86. acc, err := ks.NewAccount(pass)
  87. if err != nil {
  88. t.Fatal(err)
  89. }
  90. if _, unlocked := ks.unlocked[acc.Address]; unlocked {
  91. t.Fatal("expected account to be locked")
  92. }
  93. _, err = ks.SignHashWithPassphrase(acc, pass, testSigData)
  94. if err != nil {
  95. t.Fatal(err)
  96. }
  97. if _, unlocked := ks.unlocked[acc.Address]; unlocked {
  98. t.Fatal("expected account to be locked")
  99. }
  100. if _, err = ks.SignHashWithPassphrase(acc, "invalid passwd", testSigData); err == nil {
  101. t.Fatal("expected SignHashWithPassphrase to fail with invalid password")
  102. }
  103. }
  104. func TestTimedUnlock(t *testing.T) {
  105. dir, ks := tmpKeyStore(t, true)
  106. defer os.RemoveAll(dir)
  107. pass := "foo"
  108. a1, err := ks.NewAccount(pass)
  109. if err != nil {
  110. t.Fatal(err)
  111. }
  112. // Signing without passphrase fails because account is locked
  113. _, err = ks.SignHash(accounts.Account{Address: a1.Address}, testSigData)
  114. if err != ErrLocked {
  115. t.Fatal("Signing should've failed with ErrLocked before unlocking, got ", err)
  116. }
  117. // Signing with passphrase works
  118. if err = ks.TimedUnlock(a1, pass, 100*time.Millisecond); err != nil {
  119. t.Fatal(err)
  120. }
  121. // Signing without passphrase works because account is temp unlocked
  122. _, err = ks.SignHash(accounts.Account{Address: a1.Address}, testSigData)
  123. if err != nil {
  124. t.Fatal("Signing shouldn't return an error after unlocking, got ", err)
  125. }
  126. // Signing fails again after automatic locking
  127. time.Sleep(250 * time.Millisecond)
  128. _, err = ks.SignHash(accounts.Account{Address: a1.Address}, testSigData)
  129. if err != ErrLocked {
  130. t.Fatal("Signing should've failed with ErrLocked timeout expired, got ", err)
  131. }
  132. }
  133. func TestOverrideUnlock(t *testing.T) {
  134. dir, ks := tmpKeyStore(t, false)
  135. defer os.RemoveAll(dir)
  136. pass := "foo"
  137. a1, err := ks.NewAccount(pass)
  138. if err != nil {
  139. t.Fatal(err)
  140. }
  141. // Unlock indefinitely.
  142. if err = ks.TimedUnlock(a1, pass, 5*time.Minute); err != nil {
  143. t.Fatal(err)
  144. }
  145. // Signing without passphrase works because account is temp unlocked
  146. _, err = ks.SignHash(accounts.Account{Address: a1.Address}, testSigData)
  147. if err != nil {
  148. t.Fatal("Signing shouldn't return an error after unlocking, got ", err)
  149. }
  150. // reset unlock to a shorter period, invalidates the previous unlock
  151. if err = ks.TimedUnlock(a1, pass, 100*time.Millisecond); err != nil {
  152. t.Fatal(err)
  153. }
  154. // Signing without passphrase still works because account is temp unlocked
  155. _, err = ks.SignHash(accounts.Account{Address: a1.Address}, testSigData)
  156. if err != nil {
  157. t.Fatal("Signing shouldn't return an error after unlocking, got ", err)
  158. }
  159. // Signing fails again after automatic locking
  160. time.Sleep(250 * time.Millisecond)
  161. _, err = ks.SignHash(accounts.Account{Address: a1.Address}, testSigData)
  162. if err != ErrLocked {
  163. t.Fatal("Signing should've failed with ErrLocked timeout expired, got ", err)
  164. }
  165. }
  166. // This test should fail under -race if signing races the expiration goroutine.
  167. func TestSignRace(t *testing.T) {
  168. dir, ks := tmpKeyStore(t, false)
  169. defer os.RemoveAll(dir)
  170. // Create a test account.
  171. a1, err := ks.NewAccount("")
  172. if err != nil {
  173. t.Fatal("could not create the test account", err)
  174. }
  175. if err := ks.TimedUnlock(a1, "", 15*time.Millisecond); err != nil {
  176. t.Fatal("could not unlock the test account", err)
  177. }
  178. end := time.Now().Add(500 * time.Millisecond)
  179. for time.Now().Before(end) {
  180. if _, err := ks.SignHash(accounts.Account{Address: a1.Address}, testSigData); err == ErrLocked {
  181. return
  182. } else if err != nil {
  183. t.Errorf("Sign error: %v", err)
  184. return
  185. }
  186. time.Sleep(1 * time.Millisecond)
  187. }
  188. t.Errorf("Account did not lock within the timeout")
  189. }
  190. // Tests that the wallet notifier loop starts and stops correctly based on the
  191. // addition and removal of wallet event subscriptions.
  192. func TestWalletNotifierLifecycle(t *testing.T) {
  193. // Create a temporary kesytore to test with
  194. dir, ks := tmpKeyStore(t, false)
  195. defer os.RemoveAll(dir)
  196. // Ensure that the notification updater is not running yet
  197. time.Sleep(250 * time.Millisecond)
  198. ks.mu.RLock()
  199. updating := ks.updating
  200. ks.mu.RUnlock()
  201. if updating {
  202. t.Errorf("wallet notifier running without subscribers")
  203. }
  204. // Subscribe to the wallet feed and ensure the updater boots up
  205. updates := make(chan accounts.WalletEvent)
  206. subs := make([]event.Subscription, 2)
  207. for i := 0; i < len(subs); i++ {
  208. // Create a new subscription
  209. subs[i] = ks.Subscribe(updates)
  210. // Ensure the notifier comes online
  211. time.Sleep(250 * time.Millisecond)
  212. ks.mu.RLock()
  213. updating = ks.updating
  214. ks.mu.RUnlock()
  215. if !updating {
  216. t.Errorf("sub %d: wallet notifier not running after subscription", i)
  217. }
  218. }
  219. // Unsubscribe and ensure the updater terminates eventually
  220. for i := 0; i < len(subs); i++ {
  221. // Close an existing subscription
  222. subs[i].Unsubscribe()
  223. // Ensure the notifier shuts down at and only at the last close
  224. for k := 0; k < int(walletRefreshCycle/(250*time.Millisecond))+2; k++ {
  225. ks.mu.RLock()
  226. updating = ks.updating
  227. ks.mu.RUnlock()
  228. if i < len(subs)-1 && !updating {
  229. t.Fatalf("sub %d: event notifier stopped prematurely", i)
  230. }
  231. if i == len(subs)-1 && !updating {
  232. return
  233. }
  234. time.Sleep(250 * time.Millisecond)
  235. }
  236. }
  237. t.Errorf("wallet notifier didn't terminate after unsubscribe")
  238. }
  239. type walletEvent struct {
  240. accounts.WalletEvent
  241. a accounts.Account
  242. }
  243. // Tests that wallet notifications and correctly fired when accounts are added
  244. // or deleted from the keystore.
  245. func TestWalletNotifications(t *testing.T) {
  246. dir, ks := tmpKeyStore(t, false)
  247. defer os.RemoveAll(dir)
  248. // Subscribe to the wallet feed and collect events.
  249. var (
  250. events []walletEvent
  251. updates = make(chan accounts.WalletEvent)
  252. sub = ks.Subscribe(updates)
  253. )
  254. defer sub.Unsubscribe()
  255. go func() {
  256. for {
  257. select {
  258. case ev := <-updates:
  259. events = append(events, walletEvent{ev, ev.Wallet.Accounts()[0]})
  260. case <-sub.Err():
  261. close(updates)
  262. return
  263. }
  264. }
  265. }()
  266. // Randomly add and remove accounts.
  267. var (
  268. live = make(map[common.Address]accounts.Account)
  269. wantEvents []walletEvent
  270. )
  271. for i := 0; i < 1024; i++ {
  272. if create := len(live) == 0 || rand.Int()%4 > 0; create {
  273. // Add a new account and ensure wallet notifications arrives
  274. account, err := ks.NewAccount("")
  275. if err != nil {
  276. t.Fatalf("failed to create test account: %v", err)
  277. }
  278. live[account.Address] = account
  279. wantEvents = append(wantEvents, walletEvent{accounts.WalletEvent{Kind: accounts.WalletArrived}, account})
  280. } else {
  281. // Delete a random account.
  282. var account accounts.Account
  283. for _, a := range live {
  284. account = a
  285. break
  286. }
  287. if err := ks.Delete(account, ""); err != nil {
  288. t.Fatalf("failed to delete test account: %v", err)
  289. }
  290. delete(live, account.Address)
  291. wantEvents = append(wantEvents, walletEvent{accounts.WalletEvent{Kind: accounts.WalletDropped}, account})
  292. }
  293. }
  294. // Shut down the event collector and check events.
  295. sub.Unsubscribe()
  296. for ev := range updates {
  297. events = append(events, walletEvent{ev, ev.Wallet.Accounts()[0]})
  298. }
  299. checkAccounts(t, live, ks.Wallets())
  300. checkEvents(t, wantEvents, events)
  301. }
  302. // TestImportExport tests the import functionality of a keystore.
  303. func TestImportECDSA(t *testing.T) {
  304. dir, ks := tmpKeyStore(t, true)
  305. defer os.RemoveAll(dir)
  306. key, err := crypto.GenerateKey()
  307. if err != nil {
  308. t.Fatalf("failed to generate key: %v", key)
  309. }
  310. if _, err = ks.ImportECDSA(key, "old"); err != nil {
  311. t.Errorf("importing failed: %v", err)
  312. }
  313. if _, err = ks.ImportECDSA(key, "old"); err == nil {
  314. t.Errorf("importing same key twice succeeded")
  315. }
  316. if _, err = ks.ImportECDSA(key, "new"); err == nil {
  317. t.Errorf("importing same key twice succeeded")
  318. }
  319. }
  320. // TestImportECDSA tests the import and export functionality of a keystore.
  321. func TestImportExport(t *testing.T) {
  322. dir, ks := tmpKeyStore(t, true)
  323. defer os.RemoveAll(dir)
  324. acc, err := ks.NewAccount("old")
  325. if err != nil {
  326. t.Fatalf("failed to create account: %v", acc)
  327. }
  328. json, err := ks.Export(acc, "old", "new")
  329. if err != nil {
  330. t.Fatalf("failed to export account: %v", acc)
  331. }
  332. dir2, ks2 := tmpKeyStore(t, true)
  333. defer os.RemoveAll(dir2)
  334. if _, err = ks2.Import(json, "old", "old"); err == nil {
  335. t.Errorf("importing with invalid password succeeded")
  336. }
  337. acc2, err := ks2.Import(json, "new", "new")
  338. if err != nil {
  339. t.Errorf("importing failed: %v", err)
  340. }
  341. if acc.Address != acc2.Address {
  342. t.Error("imported account does not match exported account")
  343. }
  344. if _, err = ks2.Import(json, "new", "new"); err == nil {
  345. t.Errorf("importing a key twice succeeded")
  346. }
  347. }
  348. // TestImportRace tests the keystore on races.
  349. // This test should fail under -race if importing races.
  350. func TestImportRace(t *testing.T) {
  351. dir, ks := tmpKeyStore(t, true)
  352. defer os.RemoveAll(dir)
  353. acc, err := ks.NewAccount("old")
  354. if err != nil {
  355. t.Fatalf("failed to create account: %v", acc)
  356. }
  357. json, err := ks.Export(acc, "old", "new")
  358. if err != nil {
  359. t.Fatalf("failed to export account: %v", acc)
  360. }
  361. dir2, ks2 := tmpKeyStore(t, true)
  362. defer os.RemoveAll(dir2)
  363. var atom uint32
  364. var wg sync.WaitGroup
  365. wg.Add(2)
  366. for i := 0; i < 2; i++ {
  367. go func() {
  368. defer wg.Done()
  369. if _, err := ks2.Import(json, "new", "new"); err != nil {
  370. atomic.AddUint32(&atom, 1)
  371. }
  372. }()
  373. }
  374. wg.Wait()
  375. if atom != 1 {
  376. t.Errorf("Import is racy")
  377. }
  378. }
  379. // checkAccounts checks that all known live accounts are present in the wallet list.
  380. func checkAccounts(t *testing.T, live map[common.Address]accounts.Account, wallets []accounts.Wallet) {
  381. if len(live) != len(wallets) {
  382. t.Errorf("wallet list doesn't match required accounts: have %d, want %d", len(wallets), len(live))
  383. return
  384. }
  385. liveList := make([]accounts.Account, 0, len(live))
  386. for _, account := range live {
  387. liveList = append(liveList, account)
  388. }
  389. sort.Sort(accountsByURL(liveList))
  390. for j, wallet := range wallets {
  391. if accs := wallet.Accounts(); len(accs) != 1 {
  392. t.Errorf("wallet %d: contains invalid number of accounts: have %d, want 1", j, len(accs))
  393. } else if accs[0] != liveList[j] {
  394. t.Errorf("wallet %d: account mismatch: have %v, want %v", j, accs[0], liveList[j])
  395. }
  396. }
  397. }
  398. // checkEvents checks that all events in 'want' are present in 'have'. Events may be present multiple times.
  399. func checkEvents(t *testing.T, want []walletEvent, have []walletEvent) {
  400. for _, wantEv := range want {
  401. nmatch := 0
  402. for ; len(have) > 0; nmatch++ {
  403. if have[0].Kind != wantEv.Kind || have[0].a != wantEv.a {
  404. break
  405. }
  406. have = have[1:]
  407. }
  408. if nmatch == 0 {
  409. t.Fatalf("can't find event with Kind=%v for %x", wantEv.Kind, wantEv.a.Address)
  410. }
  411. }
  412. }
  413. func tmpKeyStore(t *testing.T, encrypted bool) (string, *KeyStore) {
  414. d, err := ioutil.TempDir("", "eth-keystore-test")
  415. if err != nil {
  416. t.Fatal(err)
  417. }
  418. newKs := NewPlaintextKeyStore
  419. if encrypted {
  420. newKs = func(kd string) *KeyStore { return NewKeyStore(kd, veryLightScryptN, veryLightScryptP) }
  421. }
  422. return d, newKs(d)
  423. }