keystore_test.go 13 KB

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