keystore_test.go 11 KB

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