1 // Copyright (c) 2014-2016 The btcsuite developers
2 package waddrmgr_test
3 4 import (
5 "encoding/hex"
6 "fmt"
7 "github.com/p9c/p9/pkg/btcaddr"
8 "os"
9 "reflect"
10 "testing"
11 "time"
12 13 "github.com/davecgh/go-spew/spew"
14 15 "github.com/p9c/p9/pkg/chaincfg"
16 "github.com/p9c/p9/pkg/chainhash"
17 "github.com/p9c/p9/pkg/snacl"
18 "github.com/p9c/p9/pkg/util"
19 "github.com/p9c/p9/pkg/waddrmgr"
20 "github.com/p9c/p9/pkg/walletdb"
21 )
22 23 // // newHash converts the passed big-endian hex string into a chainhash.Hash.
24 // // It only differs from the one available in wire in that it panics on an
25 // // error since it will only (and must only) be called with hard-coded, and
26 // // therefore known good, hashes.
27 // func newHash(// hexStr string) *chainhash.Hash {
28 // hash, e := chainhash.NewHashFromStr(hexStr)
29 // if e != nil {
30 // panic(e)
31 // }
32 // return hash
33 // }
34 35 // failingSecretKeyGen is a waddrmgr.SecretKeyGenerator that always returns
36 // snacl.ErrDecryptFailed.
37 func failingSecretKeyGen(
38 passphrase *[]byte,
39 config *waddrmgr.ScryptOptions,
40 ) (*snacl.SecretKey, error) {
41 return nil, snacl.ErrDecryptFailed
42 }
43 44 // testContext is used to store context information about a running test which
45 // is passed into helper functions. The useSpends field indicates whether or not
46 // the spend data should be empty or figure it out based on the specific test
47 // blocks provided.
48 //
49 // This is needed because the first loop where the blocks are inserted, the
50 // tests are running against the latest block and therefore none of the outputs
51 // can be spent yet.
52 //
53 // However, on subsequent runs, all blocks have been inserted and therefore some
54 // of the transaction outputs are spent.
55 type testContext struct {
56 t *testing.T
57 db walletdb.DB
58 rootManager *waddrmgr.Manager
59 manager *waddrmgr.ScopedKeyManager
60 account uint32
61 create bool
62 unlocked bool
63 watchingOnly bool
64 }
65 66 // addrType is the type of address being tested
67 type addrType byte
68 69 const (
70 addrPubKeyHash addrType = iota
71 addrScriptHash
72 )
73 74 // expectedAddr is used to house the expected return values from a managed
75 // address. Not all fields for used for all managed address types.
76 type expectedAddr struct {
77 address string
78 addressHash []byte
79 internal bool
80 compressed bool
81 // used bool
82 imported bool
83 pubKey []byte
84 privKey []byte
85 privKeyWIF string
86 script []byte
87 derivationInfo waddrmgr.DerivationPath
88 }
89 90 // testNamePrefix is a helper to return a prefix to show for test errors based
91 // on the state of the test context.
92 func testNamePrefix(tc *testContext) string {
93 prefix := "Open "
94 if tc.create {
95 prefix = "Create "
96 }
97 return prefix + fmt.Sprintf("account #%d", tc.account)
98 }
99 100 // testManagedPubKeyAddress ensures the data returned by all exported functions
101 // provided by the passed managed public key address matches the corresponding
102 // fields in the provided expected address.
103 //
104 // When the test context indicates the manager is unlocked, the private data
105 // will also be tested, otherwise, the functions which deal with private data
106 // are checked to ensure they return the correct error.
107 func testManagedPubKeyAddress(
108 tc *testContext, prefix string,
109 gotAddr waddrmgr.ManagedPubKeyAddress, wantAddr *expectedAddr,
110 ) bool {
111 // Ensure pubkey is the expected value for the managed address.
112 var gpubBytes []byte
113 if gotAddr.Compressed() {
114 gpubBytes = gotAddr.PubKey().SerializeCompressed()
115 } else {
116 gpubBytes = gotAddr.PubKey().SerializeUncompressed()
117 }
118 if !reflect.DeepEqual(gpubBytes, wantAddr.pubKey) {
119 tc.t.Errorf(
120 "%s PubKey: unexpected public key - got %x, want "+
121 "%x", prefix, gpubBytes, wantAddr.pubKey,
122 )
123 return false
124 }
125 // Ensure exported pubkey string is the expected value for the managed address.
126 gpubHex := gotAddr.ExportPubKey()
127 wantPubHex := hex.EncodeToString(wantAddr.pubKey)
128 if gpubHex != wantPubHex {
129 tc.t.Errorf(
130 "%s ExportPubKey: unexpected public key - got %s, "+
131 "want %s", prefix, gpubHex, wantPubHex,
132 )
133 return false
134 }
135 // Ensure that the derivation path has been properly re-set after the address
136 // was read from disk.
137 _, gotAddrPath, ok := gotAddr.DerivationInfo()
138 if !ok && !gotAddr.Imported() {
139 tc.t.Errorf(
140 "%s PubKey: non-imported address has empty "+
141 "derivation info", prefix,
142 )
143 return false
144 }
145 expectedDerivationInfo := wantAddr.derivationInfo
146 if gotAddrPath != expectedDerivationInfo {
147 tc.t.Errorf(
148 "%s PubKey: wrong derivation info: expected %v, "+
149 "got %v", prefix, spew.Sdump(gotAddrPath),
150 spew.Sdump(expectedDerivationInfo),
151 )
152 return false
153 }
154 // Ensure private key is the expected value for the managed address. Since this
155 // is only available when the manager is unlocked, also check for the expected
156 // error when the manager is locked.
157 gotPrivKey, e := gotAddr.PrivKey()
158 switch {
159 case tc.watchingOnly:
160 // Confirm expected watching-only error.
161 testName := fmt.Sprintf("%s PrivKey", prefix)
162 if !checkManagerError(tc.t, testName, e, waddrmgr.ErrWatchingOnly) {
163 return false
164 }
165 case tc.unlocked:
166 if e != nil {
167 tc.t.Errorf(
168 "%s PrivKey: unexpected error - got %v",
169 prefix, e,
170 )
171 return false
172 }
173 gpriv := gotPrivKey.Serialize()
174 if !reflect.DeepEqual(gpriv, wantAddr.privKey) {
175 tc.t.Errorf(
176 "%s PrivKey: unexpected private key - "+
177 "got %x, want %x", prefix, gpriv, wantAddr.privKey,
178 )
179 return false
180 }
181 default:
182 // Confirm expected locked error.
183 testName := fmt.Sprintf("%s PrivKey", prefix)
184 if !checkManagerError(tc.t, testName, e, waddrmgr.ErrLocked) {
185 return false
186 }
187 }
188 // Ensure exported private key in Wallet Import Format (WIF) is the expected
189 // value for the managed address. Since this is only available when the manager
190 // is unlocked, also check for the expected error when the manager is locked.
191 gotWIF, e := gotAddr.ExportPrivKey()
192 switch {
193 case tc.watchingOnly:
194 // Confirm expected watching-only error.
195 testName := fmt.Sprintf("%s ExportPrivKey", prefix)
196 if !checkManagerError(tc.t, testName, e, waddrmgr.ErrWatchingOnly) {
197 return false
198 }
199 case tc.unlocked:
200 if e != nil {
201 tc.t.Errorf(
202 "%s ExportPrivKey: unexpected error - "+
203 "got %v", prefix, e,
204 )
205 return false
206 }
207 if gotWIF.String() != wantAddr.privKeyWIF {
208 tc.t.Errorf(
209 "%s ExportPrivKey: unexpected WIF - got "+
210 "%v, want %v", prefix, gotWIF.String(),
211 wantAddr.privKeyWIF,
212 )
213 return false
214 }
215 default:
216 // Confirm expected locked error.
217 testName := fmt.Sprintf("%s ExportPrivKey", prefix)
218 if !checkManagerError(tc.t, testName, e, waddrmgr.ErrLocked) {
219 return false
220 }
221 }
222 // Imported addresses should return a nil derivation info.
223 if _, _, ok := gotAddr.DerivationInfo(); gotAddr.Imported() && ok {
224 tc.t.Errorf("%s Imported: expected nil derivation info", prefix)
225 return false
226 }
227 return true
228 }
229 230 // testManagedScriptAddress ensures the data returned by all exported functions
231 // provided by the passed managed script address matches the corresponding
232 // fields in the provided expected address.
233 //
234 // When the test context indicates the manager is unlocked, the private data
235 // will also be tested, otherwise, the functions which deal with private data
236 // are checked to ensure they return the correct error.
237 func testManagedScriptAddress(
238 tc *testContext,
239 prefix string,
240 gotAddr waddrmgr.ManagedScriptAddress,
241 wantAddr *expectedAddr,
242 ) bool {
243 // Ensure script is the expected value for the managed address. Since this is
244 // only available when the manager is unlocked, also check for the expected
245 // error when the manager is locked.
246 gotScript, e := gotAddr.Script()
247 switch {
248 case tc.watchingOnly:
249 // Confirm expected watching-only error.
250 testName := fmt.Sprintf("%s Script", prefix)
251 if !checkManagerError(tc.t, testName, e, waddrmgr.ErrWatchingOnly) {
252 return false
253 }
254 case tc.unlocked:
255 if e != nil {
256 tc.t.Errorf(
257 "%s Script: unexpected error - got %v",
258 prefix, e,
259 )
260 return false
261 }
262 if !reflect.DeepEqual(gotScript, wantAddr.script) {
263 tc.t.Errorf(
264 "%s Script: unexpected script - got %x, "+
265 "want %x", prefix, gotScript, wantAddr.script,
266 )
267 return false
268 }
269 default:
270 // Confirm expected locked error.
271 testName := fmt.Sprintf("%s Script", prefix)
272 if !checkManagerError(tc.t, testName, e, waddrmgr.ErrLocked) {
273 return false
274 }
275 }
276 return true
277 }
278 279 // testAddress ensures the data returned by all exported functions provided by
280 // the passed managed address matches the corresponding fields in the provided
281 // expected address. It also type asserts the managed address to determine its
282 // specific type and calls the corresponding testing functions accordingly.
283 //
284 // When the test context indicates the manager is unlocked, the private data
285 // will also be tested, otherwise, the functions which deal with private data
286 // are checked to ensure they return the correct error.
287 func testAddress(tc *testContext, prefix string, gotAddr waddrmgr.ManagedAddress, wantAddr *expectedAddr) bool {
288 if gotAddr.Account() != tc.account {
289 tc.t.Errorf(
290 "ManagedAddress.Account: unexpected account - got "+
291 "%d, want %d", gotAddr.Account(), tc.account,
292 )
293 return false
294 }
295 if gotAddr.Address().EncodeAddress() != wantAddr.address {
296 tc.t.Errorf(
297 "%s EncodeAddress: unexpected address - got %s, "+
298 "want %s", prefix, gotAddr.Address().EncodeAddress(),
299 wantAddr.address,
300 )
301 return false
302 }
303 if !reflect.DeepEqual(gotAddr.AddrHash(), wantAddr.addressHash) {
304 tc.t.Errorf(
305 "%s AddrHash: unexpected address hash - got %x, "+
306 "want %x", prefix, gotAddr.AddrHash(),
307 wantAddr.addressHash,
308 )
309 return false
310 }
311 if gotAddr.Internal() != wantAddr.internal {
312 tc.t.Errorf(
313 "%s Internal: unexpected internal flag - got %v, "+
314 "want %v", prefix, gotAddr.Internal(), wantAddr.internal,
315 )
316 return false
317 }
318 if gotAddr.Compressed() != wantAddr.compressed {
319 tc.t.Errorf(
320 "%s Compressed: unexpected compressed flag - got "+
321 "%v, want %v", prefix, gotAddr.Compressed(),
322 wantAddr.compressed,
323 )
324 return false
325 }
326 if gotAddr.Imported() != wantAddr.imported {
327 tc.t.Errorf(
328 "%s Imported: unexpected imported flag - got %v, "+
329 "want %v", prefix, gotAddr.Imported(), wantAddr.imported,
330 )
331 return false
332 }
333 switch addr := gotAddr.(type) {
334 case waddrmgr.ManagedPubKeyAddress:
335 if !testManagedPubKeyAddress(tc, prefix, addr, wantAddr) {
336 return false
337 }
338 case waddrmgr.ManagedScriptAddress:
339 if !testManagedScriptAddress(tc, prefix, addr, wantAddr) {
340 return false
341 }
342 }
343 return true
344 }
345 346 // testExternalAddresses tests several facets of external addresses such as
347 // generating multiple addresses via NextExternalAddresses, ensuring they can be
348 // retrieved by Address, and that they work properly when the manager is locked
349 // and unlocked.
350 func testExternalAddresses(tc *testContext) bool {
351 prefix := testNamePrefix(tc) + " testExternalAddresses"
352 var addrs []waddrmgr.ManagedAddress
353 if tc.create {
354 prefix = prefix + " NextExternalAddresses"
355 e := walletdb.Update(
356 tc.db, func(tx walletdb.ReadWriteTx) (e error) {
357 ns := tx.ReadWriteBucket(waddrmgrNamespaceKey)
358 addrs, e = tc.manager.NextExternalAddresses(ns, tc.account, 5)
359 return e
360 },
361 )
362 if e != nil {
363 tc.t.Errorf("%s: unexpected error: %v", prefix, e)
364 return false
365 }
366 if len(addrs) != len(expectedExternalAddrs) {
367 tc.t.Errorf(
368 "%s: unexpected number of addresses - got "+
369 "%d, want %d", prefix, len(addrs),
370 len(expectedExternalAddrs),
371 )
372 return false
373 }
374 }
375 // Setup a closure to test the results since the same tests need to be repeated
376 // with the manager locked and unlocked.
377 testResults := func() bool {
378 // Ensure the returned addresses are the expected ones. When not in the create
379 // phase, there will be no addresses in the addrs slice, so this really only
380 // runs during the first phase of the tests.
381 for i := 0; i < len(addrs); i++ {
382 prefix = fmt.Sprintf("%s ExternalAddress #%d", prefix, i)
383 if !testAddress(tc, prefix, addrs[i], &expectedExternalAddrs[i]) {
384 return false
385 }
386 }
387 // Ensure the last external address is the expected one.
388 leaPrefix := prefix + " LastExternalAddress"
389 var lastAddr waddrmgr.ManagedAddress
390 e := walletdb.View(
391 tc.db, func(tx walletdb.ReadTx) (e error) {
392 ns := tx.ReadBucket(waddrmgrNamespaceKey)
393 lastAddr, e = tc.manager.LastExternalAddress(ns, tc.account)
394 return e
395 },
396 )
397 if e != nil {
398 tc.t.Errorf("%s: unexpected error: %v", leaPrefix, e)
399 return false
400 }
401 if !testAddress(tc, leaPrefix, lastAddr, &expectedExternalAddrs[len(expectedExternalAddrs)-1]) {
402 return false
403 }
404 // Now, use the Address API to retrieve each of the expected new addresses and
405 // ensure they're accurate.
406 chainParams := tc.manager.ChainParams()
407 for i := 0; i < len(expectedExternalAddrs); i++ {
408 pkHash := expectedExternalAddrs[i].addressHash
409 utilAddr, e := btcaddr.NewPubKeyHash(
410 pkHash, chainParams,
411 )
412 if e != nil {
413 tc.t.Errorf(
414 "%s NewPubKeyHash #%d: "+
415 "unexpected error: %v", prefix, i, e,
416 )
417 return false
418 }
419 prefix = fmt.Sprintf("%s Address #%d", prefix, i)
420 var addr waddrmgr.ManagedAddress
421 e = walletdb.View(
422 tc.db, func(tx walletdb.ReadTx) (e error) {
423 ns := tx.ReadBucket(waddrmgrNamespaceKey)
424 addr, e = tc.manager.Address(ns, utilAddr)
425 return e
426 },
427 )
428 if e != nil {
429 tc.t.Errorf(
430 "%s: unexpected error: %v", prefix,
431 e,
432 )
433 return false
434 }
435 if !testAddress(tc, prefix, addr, &expectedExternalAddrs[i]) {
436 return false
437 }
438 }
439 return true
440 }
441 // Since the manager is locked at this point, the public address information is
442 // tested and the private functions are checked to ensure they return the
443 // expected error.
444 if !testResults() {
445 return false
446 }
447 // Everything after this point involves retesting with an unlocked address
448 // manager which is not possible for watching-only mode, so just exit now in
449 // that case.
450 if tc.watchingOnly {
451 return true
452 }
453 // Unlock the manager and retest all of the addresses to ensure the private
454 // information is valid as well.
455 e := walletdb.View(
456 tc.db, func(tx walletdb.ReadTx) (e error) {
457 ns := tx.ReadBucket(waddrmgrNamespaceKey)
458 return tc.rootManager.Unlock(ns, privPassphrase)
459 },
460 )
461 if e != nil {
462 tc.t.Errorf("Unlock: unexpected error: %v", e)
463 return false
464 }
465 tc.unlocked = true
466 if !testResults() {
467 return false
468 }
469 // Relock the manager for future tests.
470 if e := tc.rootManager.Lock(); E.Chk(e) {
471 tc.t.Errorf("Lock: unexpected error: %v", e)
472 return false
473 }
474 tc.unlocked = false
475 return true
476 }
477 478 // testInternalAddresses tests several facets of internal addresses such as
479 // generating multiple addresses via NextInternalAddresses, ensuring they can be
480 // retrieved by Address, and that they work properly when the manager is locked
481 // and unlocked.
482 func testInternalAddresses(tc *testContext) bool {
483 // When the address manager is not in watching-only mode, unlocked it first to
484 // ensure that address generation works correctly when the address manager is
485 // unlocked and then locked later. These tests reverse the order done in the
486 // external tests which starts with a locked manager and unlock it afterwards.
487 if !tc.watchingOnly {
488 // Unlock the manager and retest all of the addresses to ensure the private
489 // information is valid as well.
490 e := walletdb.View(
491 tc.db, func(tx walletdb.ReadTx) (e error) {
492 ns := tx.ReadBucket(waddrmgrNamespaceKey)
493 return tc.rootManager.Unlock(ns, privPassphrase)
494 },
495 )
496 if e != nil {
497 tc.t.Errorf("Unlock: unexpected error: %v", e)
498 return false
499 }
500 tc.unlocked = true
501 }
502 prefix := testNamePrefix(tc) + " testInternalAddresses"
503 var addrs []waddrmgr.ManagedAddress
504 if tc.create {
505 prefix = prefix + " NextInternalAddress"
506 e := walletdb.Update(
507 tc.db, func(tx walletdb.ReadWriteTx) (e error) {
508 ns := tx.ReadWriteBucket(waddrmgrNamespaceKey)
509 addrs, e = tc.manager.NextInternalAddresses(ns, tc.account, 5)
510 return e
511 },
512 )
513 if e != nil {
514 tc.t.Errorf("%s: unexpected error: %v", prefix, e)
515 return false
516 }
517 if len(addrs) != len(expectedInternalAddrs) {
518 tc.t.Errorf(
519 "%s: unexpected number of addresses - got "+
520 "%d, want %d", prefix, len(addrs),
521 len(expectedInternalAddrs),
522 )
523 return false
524 }
525 }
526 // Setup a closure to test the results since the same tests need to be repeated
527 // with the manager locked and unlocked.
528 testResults := func() bool {
529 // Ensure the returned addresses are the expected ones. When not in the create
530 // phase, there will be no addresses in the addrs slice, so this really only
531 // runs during the first phase of the tests.
532 for i := 0; i < len(addrs); i++ {
533 prefix = fmt.Sprintf("%s InternalAddress #%d", prefix, i)
534 if !testAddress(tc, prefix, addrs[i], &expectedInternalAddrs[i]) {
535 return false
536 }
537 }
538 // Ensure the last internal address is the expected one.
539 liaPrefix := prefix + " LastInternalAddress"
540 var lastAddr waddrmgr.ManagedAddress
541 e := walletdb.View(
542 tc.db, func(tx walletdb.ReadTx) (e error) {
543 ns := tx.ReadBucket(waddrmgrNamespaceKey)
544 lastAddr, e = tc.manager.LastInternalAddress(ns, tc.account)
545 return e
546 },
547 )
548 if e != nil {
549 tc.t.Errorf("%s: unexpected error: %v", liaPrefix, e)
550 return false
551 }
552 if !testAddress(tc, liaPrefix, lastAddr, &expectedInternalAddrs[len(expectedInternalAddrs)-1]) {
553 return false
554 }
555 // Now, use the Address API to retrieve each of the expected new addresses and
556 // ensure they're accurate.
557 chainParams := tc.manager.ChainParams()
558 for i := 0; i < len(expectedInternalAddrs); i++ {
559 pkHash := expectedInternalAddrs[i].addressHash
560 utilAddr, e := btcaddr.NewPubKeyHash(
561 pkHash, chainParams,
562 )
563 if e != nil {
564 tc.t.Errorf(
565 "%s NewPubKeyHash #%d: "+
566 "unexpected error: %v", prefix, i, e,
567 )
568 return false
569 }
570 prefix = fmt.Sprintf("%s Address #%d", prefix, i)
571 var addr waddrmgr.ManagedAddress
572 e = walletdb.View(
573 tc.db, func(tx walletdb.ReadTx) (e error) {
574 ns := tx.ReadBucket(waddrmgrNamespaceKey)
575 addr, e = tc.manager.Address(ns, utilAddr)
576 return e
577 },
578 )
579 if e != nil {
580 tc.t.Errorf(
581 "%s: unexpected error: %v", prefix,
582 e,
583 )
584 return false
585 }
586 if !testAddress(tc, prefix, addr, &expectedInternalAddrs[i]) {
587 return false
588 }
589 }
590 return true
591 }
592 // The address manager could either be locked or unlocked here depending on
593 // whether or not it's a watching-only manager. When it's unlocked, this will
594 // test both the public and private address data are accurate. When it's locked,
595 // it must be watching-only, so only the public address information is tested
596 // and the private functions are checked to ensure they return the expected
597 // ErrWatchingOnly error.
598 if !testResults() {
599 return false
600 }
601 // Everything after this point involves locking the address manager and
602 // retesting the addresses with a locked manager. However, for watching-only
603 // mode, this has already happened, so just exit now in that case.
604 if tc.watchingOnly {
605 return true
606 }
607 // Lock the manager and retest all of the addresses to ensure the public
608 // information remains valid and the private functions return the expected
609 // error.
610 if e := tc.rootManager.Lock(); E.Chk(e) {
611 tc.t.Errorf("Lock: unexpected error: %v", e)
612 return false
613 }
614 tc.unlocked = false
615 if !testResults() {
616 return false
617 }
618 return true
619 }
620 621 // testLocking tests the basic locking semantics of the address manager work as
622 // expected. Other tests ensure addresses behave as expected under locked and
623 // unlocked conditions.
624 func testLocking(tc *testContext) bool {
625 if tc.unlocked {
626 tc.t.Error("testLocking called with an unlocked manager")
627 return false
628 }
629 if !tc.rootManager.IsLocked() {
630 tc.t.Error("IsLocked: returned false on locked manager")
631 return false
632 }
633 // Locking an already lock manager should return an error. The error should be
634 // ErrLocked or ErrWatchingOnly depending on the type of the address manager.
635 e := tc.rootManager.Lock()
636 wantErrCode := waddrmgr.ErrLocked
637 if tc.watchingOnly {
638 wantErrCode = waddrmgr.ErrWatchingOnly
639 }
640 if !checkManagerError(tc.t, "Lock", e, wantErrCode) {
641 return false
642 }
643 // Ensure unlocking with the correct passphrase doesn't return any unexpected
644 // errors and the manager properly reports it is unlocked. Since watching-only
645 // address managers can't be unlocked, also ensure the correct error for that
646 // case.
647 e = walletdb.View(
648 tc.db, func(tx walletdb.ReadTx) (e error) {
649 ns := tx.ReadBucket(waddrmgrNamespaceKey)
650 return tc.rootManager.Unlock(ns, privPassphrase)
651 },
652 )
653 if tc.watchingOnly {
654 if !checkManagerError(tc.t, "Unlock", e, waddrmgr.ErrWatchingOnly) {
655 return false
656 }
657 } else if e != nil {
658 tc.t.Errorf("Unlock: unexpected error: %v", e)
659 return false
660 }
661 if !tc.watchingOnly && tc.rootManager.IsLocked() {
662 tc.t.Error("IsLocked: returned true on unlocked manager")
663 return false
664 }
665 // Unlocking the manager again is allowed. Since watching-only address managers
666 // can't be unlocked, also ensure the correct error for that case.
667 e = walletdb.View(
668 tc.db, func(tx walletdb.ReadTx) (e error) {
669 ns := tx.ReadBucket(waddrmgrNamespaceKey)
670 return tc.rootManager.Unlock(ns, privPassphrase)
671 },
672 )
673 if tc.watchingOnly {
674 if !checkManagerError(tc.t, "Unlock2", e, waddrmgr.ErrWatchingOnly) {
675 return false
676 }
677 } else if e != nil {
678 tc.t.Errorf("Unlock: unexpected error: %v", e)
679 return false
680 }
681 if !tc.watchingOnly && tc.rootManager.IsLocked() {
682 tc.t.Error("IsLocked: returned true on unlocked manager")
683 return false
684 }
685 // Unlocking the manager with an invalid passphrase must result in an error and
686 // a locked manager.
687 e = walletdb.View(
688 tc.db, func(tx walletdb.ReadTx) (e error) {
689 ns := tx.ReadBucket(waddrmgrNamespaceKey)
690 return tc.rootManager.Unlock(ns, []byte("invalidpassphrase"))
691 },
692 )
693 wantErrCode = waddrmgr.ErrWrongPassphrase
694 if tc.watchingOnly {
695 wantErrCode = waddrmgr.ErrWatchingOnly
696 }
697 if !checkManagerError(tc.t, "Unlock", e, wantErrCode) {
698 return false
699 }
700 if !tc.rootManager.IsLocked() {
701 tc.t.Error(
702 "IsLocked: manager is unlocked after failed unlock " +
703 "attempt",
704 )
705 return false
706 }
707 return true
708 }
709 710 // testImportPrivateKey tests that importing private keys works properly. It
711 // ensures they can be retrieved by Address after they have been imported and
712 // the addresses give the expected values when the manager is locked and
713 // unlocked.
714 //
715 // This function expects the manager is already locked when called and returns
716 // with the manager locked.
717 func testImportPrivateKey(tc *testContext) bool {
718 tests := []struct {
719 name string
720 in string
721 blockstamp waddrmgr.BlockStamp
722 expected expectedAddr
723 }{
724 {
725 name: "wif for uncompressed pubkey address",
726 in: "5HueCGU8rMjxEXxiPuD5BDku4MkFqeZyd4dZ1jvhTVqvbTLvyTJ",
727 expected: expectedAddr{
728 address: "1GAehh7TsJAHuUAeKZcXf5CnwuGuGgyX2S",
729 addressHash: hexToBytes("a65d1a239d4ec666643d350c7bb8fc44d2881128"),
730 internal: false,
731 imported: true,
732 compressed: false,
733 pubKey: hexToBytes(
734 "04d0de0aaeaefad02b8bdc8a01a1b8b11c696bd3" +
735 "d66a2c5f10780d95b7df42645cd85228a6fb29940e858e7e558" +
736 "42ae2bd115d1ed7cc0e82d934e929c97648cb0a",
737 ),
738 privKey: hexToBytes("0c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d"),
739 // privKeyWIF is set to the in field during tests
740 },
741 },
742 {
743 name: "wif for compressed pubkey address",
744 in: "KwdMAjGmerYanjeui5SHS7JkmpZvVipYvB2LJGU1ZxJwYvP98617",
745 expected: expectedAddr{
746 address: "1LoVGDgRs9hTfTNJNuXKSpywcbdvwRXpmK",
747 addressHash: hexToBytes("d9351dcbad5b8f3b8bfa2f2cdc85c28118ca9326"),
748 internal: false,
749 imported: true,
750 compressed: true,
751 pubKey: hexToBytes("02d0de0aaeaefad02b8bdc8a01a1b8b11c696bd3d66a2c5f10780d95b7df42645c"),
752 privKey: hexToBytes("0c28fca386c7a227600b2fe50b7cae11ec86d3bf1fbe471be89827e19d72aa1d"),
753 // privKeyWIF is set to the in field during tests
754 },
755 },
756 }
757 // The manager must be unlocked to import a private key, however a watching-only
758 // manager can't be unlocked.
759 if !tc.watchingOnly {
760 e := walletdb.View(
761 tc.db, func(tx walletdb.ReadTx) (e error) {
762 ns := tx.ReadBucket(waddrmgrNamespaceKey)
763 return tc.rootManager.Unlock(ns, privPassphrase)
764 },
765 )
766 if e != nil {
767 tc.t.Errorf("Unlock: unexpected error: %v", e)
768 return false
769 }
770 tc.unlocked = true
771 }
772 // Only import the private keys when in the create phase of testing.
773 tc.account = waddrmgr.ImportedAddrAccount
774 prefix := testNamePrefix(tc) + " testImportPrivateKey"
775 if tc.create {
776 for i, test := range tests {
777 test.expected.privKeyWIF = test.in
778 wif, e := util.DecodeWIF(test.in)
779 if e != nil {
780 tc.t.Errorf(
781 "%s DecodeWIF #%d (%s): unexpected "+
782 "error: %v", prefix, i, test.name, e,
783 )
784 continue
785 }
786 var addr waddrmgr.ManagedPubKeyAddress
787 e = walletdb.Update(
788 tc.db, func(tx walletdb.ReadWriteTx) (e error) {
789 ns := tx.ReadWriteBucket(waddrmgrNamespaceKey)
790 addr, e = tc.manager.ImportPrivateKey(ns, wif, &test.blockstamp)
791 return e
792 },
793 )
794 if e != nil {
795 tc.t.Errorf(
796 "%s ImportPrivateKey #%d (%s): "+
797 "unexpected error: %v", prefix, i,
798 test.name, e,
799 )
800 continue
801 }
802 if !testAddress(
803 tc, prefix+" ImportPrivateKey", addr,
804 &test.expected,
805 ) {
806 continue
807 }
808 }
809 }
810 // Setup a closure to test the results since the same tests need to be repeated
811 // with the manager unlocked and locked.
812 chainParams := tc.manager.ChainParams()
813 testResults := func() bool {
814 failed := false
815 for i, test := range tests {
816 test.expected.privKeyWIF = test.in
817 // Use the Address API to retrieve each of the expected new addresses and ensure
818 // they're accurate.
819 utilAddr, e := btcaddr.NewPubKeyHash(
820 test.expected.addressHash, chainParams,
821 )
822 if e != nil {
823 tc.t.Errorf(
824 "%s NewPubKeyHash #%d (%s): "+
825 "unexpected error: %v", prefix, i,
826 test.name, e,
827 )
828 failed = true
829 continue
830 }
831 taPrefix := fmt.Sprintf(
832 "%s Address #%d (%s)", prefix,
833 i, test.name,
834 )
835 var ma waddrmgr.ManagedAddress
836 e = walletdb.View(
837 tc.db, func(tx walletdb.ReadTx) (e error) {
838 ns := tx.ReadBucket(waddrmgrNamespaceKey)
839 ma, e = tc.manager.Address(ns, utilAddr)
840 return e
841 },
842 )
843 if e != nil {
844 tc.t.Errorf(
845 "%s: unexpected error: %v", taPrefix,
846 e,
847 )
848 failed = true
849 continue
850 }
851 if !testAddress(tc, taPrefix, ma, &test.expected) {
852 failed = true
853 continue
854 }
855 }
856 return !failed
857 }
858 // The address manager could either be locked or unlocked here depending on
859 // whether or not it's a watching-only manager. When it's unlocked, this will
860 // test both the public and private address data are accurate. When it's locked,
861 // it must be watching-only, so only the public address information is tested
862 // and the private functions are checked to ensure they return the expected
863 // ErrWatchingOnly error.
864 if !testResults() {
865 return false
866 }
867 // Everything after this point involves locking the address manager and
868 // retesting the addresses with a locked manager. However, for watching-only
869 // mode, this has already happened, so just exit now in that case.
870 if tc.watchingOnly {
871 return true
872 }
873 // Lock the manager and retest all of the addresses to ensure the private
874 // information returns the expected error.
875 if e := tc.rootManager.Lock(); E.Chk(e) {
876 tc.t.Errorf("Lock: unexpected error: %v", e)
877 return false
878 }
879 tc.unlocked = false
880 if !testResults() {
881 return false
882 }
883 return true
884 }
885 886 // testImportScript tests that importing scripts works properly. It ensures they
887 // can be retrieved by Address after they have been imported and the addresses
888 // give the expected values when the manager is locked and unlocked.
889 //
890 // This function expects the manager is already locked when called and returns
891 // with the manager locked.
892 func testImportScript(tc *testContext) bool {
893 tests := []struct {
894 name string
895 in []byte
896 blockstamp waddrmgr.BlockStamp
897 expected expectedAddr
898 }{
899 {
900 name: "p2sh uncompressed pubkey",
901 in: hexToBytes(
902 "41048b65a0e6bb200e6dac05e74281b1ab9a41e8" +
903 "0006d6b12d8521e09981da97dd96ac72d24d1a7d" +
904 "ed9493a9fc20fdb4a714808f0b680f1f1d935277" +
905 "48b5e3f629ffac",
906 ),
907 expected: expectedAddr{
908 address: "3MbyWAu9UaoBewR3cArF1nwf4aQgVwzrA5",
909 addressHash: hexToBytes("da6e6a632d96dc5530d7b3c9f3017725d023093e"),
910 internal: false,
911 imported: true,
912 compressed: false,
913 // script is set to the in field during tests.
914 },
915 },
916 {
917 name: "p2sh multisig",
918 in: hexToBytes(
919 "524104cb9c3c222c5f7a7d3b9bd152f363a0b6d5" +
920 "4c9eb312c4d4f9af1e8551b6c421a6a4ab0e2910" +
921 "5f24de20ff463c1c91fcf3bf662cdde4783d4799" +
922 "f787cb7c08869b4104ccc588420deeebea22a7e9" +
923 "00cc8b68620d2212c374604e3487ca08f1ff3ae1" +
924 "2bdc639514d0ec8612a2d3c519f084d9a00cbbe3" +
925 "b53d071e9b09e71e610b036aa24104ab47ad1939" +
926 "edcb3db65f7fedea62bbf781c5410d3f22a7a3a5" +
927 "6ffefb2238af8627363bdf2ed97c1f89784a1aec" +
928 "db43384f11d2acc64443c7fc299cef0400421a53ae",
929 ),
930 expected: expectedAddr{
931 address: "34CRZpt8j81rgh9QhzuBepqPi4cBQSjhjr",
932 addressHash: hexToBytes("1b800cec1fe92222f36a502c139bed47c5959715"),
933 internal: false,
934 imported: true,
935 compressed: false,
936 // script is set to the in field during tests.
937 },
938 },
939 }
940 // The manager must be unlocked to import a private key and also for testing
941 // private data. However, a watching-only manager can't be unlocked.
942 if !tc.watchingOnly {
943 e := walletdb.View(
944 tc.db, func(tx walletdb.ReadTx) (e error) {
945 ns := tx.ReadBucket(waddrmgrNamespaceKey)
946 return tc.rootManager.Unlock(ns, privPassphrase)
947 },
948 )
949 if e != nil {
950 tc.t.Errorf("Unlock: unexpected error: %v", e)
951 return false
952 }
953 tc.unlocked = true
954 }
955 // Only import the scripts when in the create phase of testing.
956 tc.account = waddrmgr.ImportedAddrAccount
957 prefix := testNamePrefix(tc)
958 if tc.create {
959 for i, test := range tests {
960 test.expected.script = test.in
961 prefix = fmt.Sprintf(
962 "%s ImportScript #%d (%s)", prefix,
963 i, test.name,
964 )
965 var addr waddrmgr.ManagedScriptAddress
966 e := walletdb.Update(
967 tc.db, func(tx walletdb.ReadWriteTx) (e error) {
968 ns := tx.ReadWriteBucket(waddrmgrNamespaceKey)
969 addr, e = tc.manager.ImportScript(ns, test.in, &test.blockstamp)
970 return e
971 },
972 )
973 if e != nil {
974 tc.t.Errorf(
975 "%s: unexpected error: %v", prefix,
976 e,
977 )
978 continue
979 }
980 if !testAddress(tc, prefix, addr, &test.expected) {
981 continue
982 }
983 }
984 }
985 // Setup a closure to test the results since the same tests need to be repeated
986 // with the manager unlocked and locked.
987 chainParams := tc.manager.ChainParams()
988 testResults := func() bool {
989 failed := false
990 for i, test := range tests {
991 test.expected.script = test.in
992 // Use the Address API to retrieve each of the expected new addresses and ensure
993 // they're accurate.
994 utilAddr, e := btcaddr.NewScriptHash(
995 test.in,
996 chainParams,
997 )
998 if e != nil {
999 tc.t.Errorf(
1000 "%s NewScriptHash #%d (%s): "+
1001 "unexpected error: %v", prefix, i,
1002 test.name, e,
1003 )
1004 failed = true
1005 continue
1006 }
1007 taPrefix := fmt.Sprintf(
1008 "%s Address #%d (%s)", prefix,
1009 i, test.name,
1010 )
1011 var ma waddrmgr.ManagedAddress
1012 e = walletdb.View(
1013 tc.db, func(tx walletdb.ReadTx) (e error) {
1014 ns := tx.ReadBucket(waddrmgrNamespaceKey)
1015 ma, e = tc.manager.Address(ns, utilAddr)
1016 return e
1017 },
1018 )
1019 if e != nil {
1020 tc.t.Errorf(
1021 "%s: unexpected error: %v", taPrefix,
1022 e,
1023 )
1024 failed = true
1025 continue
1026 }
1027 if !testAddress(tc, taPrefix, ma, &test.expected) {
1028 failed = true
1029 continue
1030 }
1031 }
1032 return !failed
1033 }
1034 // The address manager could either be locked or unlocked here depending on
1035 // whether or not it's a watching-only manager. When it's unlocked, this will
1036 // test both the public and private address data are accurate. When it's locked,
1037 // it must be watching-only, so only the public address information is tested
1038 // and the private functions are checked to ensure they return the expected
1039 // ErrWatchingOnly error.
1040 if !testResults() {
1041 return false
1042 }
1043 // Everything after this point involves locking the address manager and
1044 // retesting the addresses with a locked manager. However, for watching-only
1045 // mode, this has already happened, so just exit now in that case.
1046 if tc.watchingOnly {
1047 return true
1048 }
1049 // Lock the manager and retest all of the addresses to ensure the private
1050 // information returns the expected error.
1051 if e := tc.rootManager.Lock(); E.Chk(e) {
1052 tc.t.Errorf("Lock: unexpected error: %v", e)
1053 return false
1054 }
1055 tc.unlocked = false
1056 if !testResults() {
1057 return false
1058 }
1059 return true
1060 }
1061 1062 // testMarkUsed ensures used addresses are flagged as such.
1063 func testMarkUsed(tc *testContext) bool {
1064 tests := []struct {
1065 name string
1066 typ addrType
1067 in []byte
1068 }{
1069 {
1070 name: "managed address",
1071 typ: addrPubKeyHash,
1072 in: hexToBytes("2ef94abb9ee8f785d087c3ec8d6ee467e92d0d0a"),
1073 },
1074 {
1075 name: "script address",
1076 typ: addrScriptHash,
1077 in: hexToBytes("da6e6a632d96dc5530d7b3c9f3017725d023093e"),
1078 },
1079 }
1080 prefix := "MarkUsed"
1081 chainParams := tc.manager.ChainParams()
1082 for i, test := range tests {
1083 addrHash := test.in
1084 var addr btcaddr.Address
1085 var e error
1086 switch test.typ {
1087 case addrPubKeyHash:
1088 addr, e = btcaddr.NewPubKeyHash(addrHash, chainParams)
1089 case addrScriptHash:
1090 addr, e = btcaddr.NewScriptHashFromHash(addrHash, chainParams)
1091 default:
1092 panic("unreachable")
1093 }
1094 if e != nil {
1095 tc.t.Errorf("%s #%d: NewAddress unexpected error: %v", prefix, i, e)
1096 continue
1097 }
1098 e = walletdb.Update(
1099 tc.db, func(tx walletdb.ReadWriteTx) (e error) {
1100 ns := tx.ReadWriteBucket(waddrmgrNamespaceKey)
1101 maddr, e := tc.manager.Address(ns, addr)
1102 if e != nil {
1103 tc.t.Errorf("%s #%d: Address unexpected error: %v", prefix, i, e)
1104 return nil
1105 }
1106 if tc.create {
1107 // Test that initially the address is not flagged as used
1108 used := maddr.Used(ns)
1109 if used != false {
1110 tc.t.Errorf(
1111 "%s #%d: unexpected used flag -- got "+
1112 "%v, want %v", prefix, i, used, false,
1113 )
1114 }
1115 }
1116 e = tc.manager.MarkUsed(ns, addr)
1117 if e != nil {
1118 tc.t.Errorf("%s #%d: unexpected error: %v", prefix, i, e)
1119 return nil
1120 }
1121 used := maddr.Used(ns)
1122 if used != true {
1123 tc.t.Errorf(
1124 "%s #%d: unexpected used flag -- got "+
1125 "%v, want %v", prefix, i, used, true,
1126 )
1127 }
1128 return nil
1129 },
1130 )
1131 if e != nil {
1132 tc.t.Errorf("Unexpected error %v", e)
1133 }
1134 }
1135 return true
1136 }
1137 1138 // testChangePassphrase ensures changes both the public and private passphrases
1139 // works as intended.
1140 func testChangePassphrase(tc *testContext) bool {
1141 // Force an error when changing the passphrase due to failure to generate a new
1142 // secret key by replacing the generation function one that intentionally
1143 // errors.
1144 testName := "ChangePassphrase (public) with invalid new secret key"
1145 oldKeyGen := waddrmgr.SetSecretKeyGen(failingSecretKeyGen)
1146 e := walletdb.Update(
1147 tc.db, func(tx walletdb.ReadWriteTx) (e error) {
1148 ns := tx.ReadWriteBucket(waddrmgrNamespaceKey)
1149 return tc.rootManager.ChangePassphrase(
1150 ns, pubPassphrase, pubPassphrase2, false, fastScrypt,
1151 )
1152 },
1153 )
1154 if !checkManagerError(tc.t, testName, e, waddrmgr.ErrCrypto) {
1155 return false
1156 }
1157 // Attempt to change public passphrase with invalid old passphrase.
1158 testName = "ChangePassphrase (public) with invalid old passphrase"
1159 waddrmgr.SetSecretKeyGen(oldKeyGen)
1160 e = walletdb.Update(
1161 tc.db, func(tx walletdb.ReadWriteTx) (e error) {
1162 ns := tx.ReadWriteBucket(waddrmgrNamespaceKey)
1163 return tc.rootManager.ChangePassphrase(
1164 ns, []byte("bogus"), pubPassphrase2, false, fastScrypt,
1165 )
1166 },
1167 )
1168 if !checkManagerError(tc.t, testName, e, waddrmgr.ErrWrongPassphrase) {
1169 return false
1170 }
1171 // Change the public passphrase.
1172 testName = "ChangePassphrase (public)"
1173 e = walletdb.Update(
1174 tc.db, func(tx walletdb.ReadWriteTx) (e error) {
1175 ns := tx.ReadWriteBucket(waddrmgrNamespaceKey)
1176 return tc.rootManager.ChangePassphrase(
1177 ns, pubPassphrase, pubPassphrase2, false, fastScrypt,
1178 )
1179 },
1180 )
1181 if e != nil {
1182 tc.t.Errorf("%s: unexpected error: %v", testName, e)
1183 return false
1184 }
1185 // Ensure the public passphrase was successfully changed.
1186 if !tc.rootManager.TstCheckPublicPassphrase(pubPassphrase2) {
1187 tc.t.Errorf("%s: passphrase does not match", testName)
1188 return false
1189 }
1190 // Change the private passphrase back to what it was.
1191 e = walletdb.Update(
1192 tc.db, func(tx walletdb.ReadWriteTx) (e error) {
1193 ns := tx.ReadWriteBucket(waddrmgrNamespaceKey)
1194 return tc.rootManager.ChangePassphrase(
1195 ns, pubPassphrase2, pubPassphrase, false, fastScrypt,
1196 )
1197 },
1198 )
1199 if e != nil {
1200 tc.t.Errorf("%s: unexpected error: %v", testName, e)
1201 return false
1202 }
1203 // Attempt to change private passphrase with invalid old passphrase. The error
1204 // should be ErrWrongPassphrase or ErrWatchingOnly depending on the type of the
1205 // address manager.
1206 testName = "ChangePassphrase (private) with invalid old passphrase"
1207 e = walletdb.Update(
1208 tc.db, func(tx walletdb.ReadWriteTx) (e error) {
1209 ns := tx.ReadWriteBucket(waddrmgrNamespaceKey)
1210 return tc.rootManager.ChangePassphrase(
1211 ns, []byte("bogus"), privPassphrase2, true, fastScrypt,
1212 )
1213 },
1214 )
1215 wantErrCode := waddrmgr.ErrWrongPassphrase
1216 if tc.watchingOnly {
1217 wantErrCode = waddrmgr.ErrWatchingOnly
1218 }
1219 if !checkManagerError(tc.t, testName, e, wantErrCode) {
1220 return false
1221 }
1222 // Everything after this point involves testing that the private passphrase for
1223 // the address manager can be changed successfully. This is not possible for
1224 // watching-only mode, so just exit now in that case.
1225 if tc.watchingOnly {
1226 return true
1227 }
1228 // Change the private passphrase.
1229 testName = "ChangePassphrase (private)"
1230 e = walletdb.Update(
1231 tc.db, func(tx walletdb.ReadWriteTx) (e error) {
1232 ns := tx.ReadWriteBucket(waddrmgrNamespaceKey)
1233 return tc.rootManager.ChangePassphrase(
1234 ns, privPassphrase, privPassphrase2, true, fastScrypt,
1235 )
1236 },
1237 )
1238 if e != nil {
1239 tc.t.Errorf("%s: unexpected error: %v", testName, e)
1240 return false
1241 }
1242 // Unlock the manager with the new passphrase to ensure it changed as expected.
1243 e = walletdb.Update(
1244 tc.db, func(tx walletdb.ReadWriteTx) (e error) {
1245 ns := tx.ReadWriteBucket(waddrmgrNamespaceKey)
1246 return tc.rootManager.Unlock(ns, privPassphrase2)
1247 },
1248 )
1249 if e != nil {
1250 tc.t.Errorf(
1251 "%s: failed to unlock with new private "+
1252 "passphrase: %v", testName, e,
1253 )
1254 return false
1255 }
1256 tc.unlocked = true
1257 // Change the private passphrase back to what it was while the manager is
1258 // unlocked to ensure that path works properly as well.
1259 e = walletdb.Update(
1260 tc.db, func(tx walletdb.ReadWriteTx) (e error) {
1261 ns := tx.ReadWriteBucket(waddrmgrNamespaceKey)
1262 return tc.rootManager.ChangePassphrase(
1263 ns, privPassphrase2, privPassphrase, true, fastScrypt,
1264 )
1265 },
1266 )
1267 if e != nil {
1268 tc.t.Errorf("%s: unexpected error: %v", testName, e)
1269 return false
1270 }
1271 if tc.rootManager.IsLocked() {
1272 tc.t.Errorf("%s: manager is locked", testName)
1273 return false
1274 }
1275 // Relock the manager for future tests.
1276 if e := tc.rootManager.Lock(); E.Chk(e) {
1277 tc.t.Errorf("Lock: unexpected error: %v", e)
1278 return false
1279 }
1280 tc.unlocked = false
1281 return true
1282 }
1283 1284 // testNewAccount tests the new account creation func of the address manager
1285 // works as expected.
1286 func testNewAccount(tc *testContext) bool {
1287 if tc.watchingOnly {
1288 // Creating new accounts in watching-only mode should return ErrWatchingOnly
1289 e := walletdb.Update(
1290 tc.db, func(tx walletdb.ReadWriteTx) (e error) {
1291 ns := tx.ReadWriteBucket(waddrmgrNamespaceKey)
1292 _, e = tc.manager.NewAccount(ns, "test")
1293 return e
1294 },
1295 )
1296 if !checkManagerError(
1297 tc.t, "Create account in watching-only mode", e,
1298 waddrmgr.ErrWatchingOnly,
1299 ) {
1300 tc.manager.Close()
1301 return false
1302 }
1303 return true
1304 }
1305 // Creating new accounts when wallet is locked should return ErrLocked
1306 e := walletdb.Update(
1307 tc.db, func(tx walletdb.ReadWriteTx) (e error) {
1308 ns := tx.ReadWriteBucket(waddrmgrNamespaceKey)
1309 _, e = tc.manager.NewAccount(ns, "test")
1310 return e
1311 },
1312 )
1313 if !checkManagerError(
1314 tc.t, "Create account when wallet is locked", e,
1315 waddrmgr.ErrLocked,
1316 ) {
1317 tc.manager.Close()
1318 return false
1319 }
1320 // Unlock the wallet to decrypt cointype keys required to derive account keys
1321 e = walletdb.Update(
1322 tc.db, func(tx walletdb.ReadWriteTx) (e error) {
1323 ns := tx.ReadWriteBucket(waddrmgrNamespaceKey)
1324 e = tc.rootManager.Unlock(ns, privPassphrase)
1325 return e
1326 },
1327 )
1328 if e != nil {
1329 tc.t.Errorf("Unlock: unexpected error: %v", e)
1330 return false
1331 }
1332 tc.unlocked = true
1333 testName := "acct-create"
1334 expectedAccount := tc.account + 1
1335 if !tc.create {
1336 // Create a new account in open mode
1337 testName = "acct-open"
1338 expectedAccount++
1339 }
1340 var account uint32
1341 e = walletdb.Update(
1342 tc.db, func(tx walletdb.ReadWriteTx) (e error) {
1343 ns := tx.ReadWriteBucket(waddrmgrNamespaceKey)
1344 account, e = tc.manager.NewAccount(ns, testName)
1345 return e
1346 },
1347 )
1348 if e != nil {
1349 tc.t.Errorf("NewAccount: unexpected error: %v", e)
1350 return false
1351 }
1352 if account != expectedAccount {
1353 tc.t.Errorf(
1354 "NewAccount "+
1355 "account mismatch -- got %d, "+
1356 "want %d", account, expectedAccount,
1357 )
1358 return false
1359 }
1360 // Test duplicate account name error
1361 e = walletdb.Update(
1362 tc.db, func(tx walletdb.ReadWriteTx) (e error) {
1363 ns := tx.ReadWriteBucket(waddrmgrNamespaceKey)
1364 _, e = tc.manager.NewAccount(ns, testName)
1365 return e
1366 },
1367 )
1368 wantErrCode := waddrmgr.ErrDuplicateAccount
1369 if !checkManagerError(tc.t, testName, e, wantErrCode) {
1370 return false
1371 }
1372 // Test account name validation
1373 testName = "" // Empty account names are not allowed
1374 e = walletdb.Update(
1375 tc.db, func(tx walletdb.ReadWriteTx) (e error) {
1376 ns := tx.ReadWriteBucket(waddrmgrNamespaceKey)
1377 _, e = tc.manager.NewAccount(ns, testName)
1378 return e
1379 },
1380 )
1381 wantErrCode = waddrmgr.ErrInvalidAccount
1382 if !checkManagerError(tc.t, testName, e, wantErrCode) {
1383 return false
1384 }
1385 testName = "imported" // A reserved account name
1386 e = walletdb.Update(
1387 tc.db, func(tx walletdb.ReadWriteTx) (e error) {
1388 ns := tx.ReadWriteBucket(waddrmgrNamespaceKey)
1389 _, e = tc.manager.NewAccount(ns, testName)
1390 return e
1391 },
1392 )
1393 wantErrCode = waddrmgr.ErrInvalidAccount
1394 if !checkManagerError(tc.t, testName, e, wantErrCode) {
1395 return false
1396 }
1397 return true
1398 }
1399 1400 // testLookupAccount tests the basic account lookup func of the address manager
1401 // works as expected.
1402 func testLookupAccount(tc *testContext) bool {
1403 // Lookup accounts created earlier in testNewAccount
1404 expectedAccounts := map[string]uint32{
1405 waddrmgr.TstDefaultAccountName: waddrmgr.DefaultAccountNum,
1406 waddrmgr.ImportedAddrAccountName: waddrmgr.ImportedAddrAccount,
1407 }
1408 for acctName, expectedAccount := range expectedAccounts {
1409 var account uint32
1410 e := walletdb.View(
1411 tc.db, func(tx walletdb.ReadTx) (e error) {
1412 ns := tx.ReadBucket(waddrmgrNamespaceKey)
1413 account, e = tc.manager.LookupAccount(ns, acctName)
1414 return e
1415 },
1416 )
1417 if e != nil {
1418 tc.t.Errorf("LookupAccount: unexpected error: %v", e)
1419 return false
1420 }
1421 if account != expectedAccount {
1422 tc.t.Errorf(
1423 "LookupAccount "+
1424 "account mismatch -- got %d, "+
1425 "want %d", account, expectedAccount,
1426 )
1427 return false
1428 }
1429 }
1430 // Test account not found error
1431 testName := "non existent account"
1432 e := walletdb.View(
1433 tc.db, func(tx walletdb.ReadTx) (e error) {
1434 ns := tx.ReadBucket(waddrmgrNamespaceKey)
1435 _, e = tc.manager.LookupAccount(ns, testName)
1436 return e
1437 },
1438 )
1439 wantErrCode := waddrmgr.ErrAccountNotFound
1440 if !checkManagerError(tc.t, testName, e, wantErrCode) {
1441 return false
1442 }
1443 // Test last account
1444 var lastAccount uint32
1445 e = walletdb.View(
1446 tc.db, func(tx walletdb.ReadTx) (e error) {
1447 ns := tx.ReadBucket(waddrmgrNamespaceKey)
1448 lastAccount, e = tc.manager.LastAccount(ns)
1449 return e
1450 },
1451 )
1452 var expectedLastAccount uint32
1453 expectedLastAccount = 1
1454 if !tc.create {
1455 // Existing wallet manager will have 3 accounts
1456 expectedLastAccount = 2
1457 }
1458 if lastAccount != expectedLastAccount {
1459 tc.t.Errorf(
1460 "LookupAccount "+
1461 "account mismatch -- got %d, "+
1462 "want %d", lastAccount, expectedLastAccount,
1463 )
1464 return false
1465 }
1466 // Test account lookup for default account adddress
1467 var expectedAccount uint32
1468 for i, addr := range expectedAddrs {
1469 addr, e := btcaddr.NewPubKeyHash(
1470 addr.addressHash,
1471 tc.manager.ChainParams(),
1472 )
1473 if e != nil {
1474 tc.t.Errorf("AddrAccount #%d: unexpected error: %v", i, e)
1475 return false
1476 }
1477 var account uint32
1478 e = walletdb.View(
1479 tc.db, func(tx walletdb.ReadTx) (e error) {
1480 ns := tx.ReadBucket(waddrmgrNamespaceKey)
1481 account, e = tc.manager.AddrAccount(ns, addr)
1482 return e
1483 },
1484 )
1485 if e != nil {
1486 tc.t.Errorf("AddrAccount #%d: unexpected error: %v", i, e)
1487 return false
1488 }
1489 if account != expectedAccount {
1490 tc.t.Errorf(
1491 "AddrAccount "+
1492 "account mismatch -- got %d, "+
1493 "want %d", account, expectedAccount,
1494 )
1495 return false
1496 }
1497 }
1498 return true
1499 }
1500 1501 // testRenameAccount tests the rename account func of the address manager works
1502 // as expected.
1503 func testRenameAccount(tc *testContext) bool {
1504 var acctName string
1505 e := walletdb.View(
1506 tc.db, func(tx walletdb.ReadTx) (e error) {
1507 ns := tx.ReadBucket(waddrmgrNamespaceKey)
1508 acctName, e = tc.manager.AccountName(ns, tc.account)
1509 return e
1510 },
1511 )
1512 if e != nil {
1513 tc.t.Errorf("AccountName: unexpected error: %v", e)
1514 return false
1515 }
1516 testName := acctName + "-renamed"
1517 e = walletdb.Update(
1518 tc.db, func(tx walletdb.ReadWriteTx) (e error) {
1519 ns := tx.ReadWriteBucket(waddrmgrNamespaceKey)
1520 return tc.manager.RenameAccount(ns, tc.account, testName)
1521 },
1522 )
1523 if e != nil {
1524 tc.t.Errorf("RenameAccount: unexpected error: %v", e)
1525 return false
1526 }
1527 var newName string
1528 e = walletdb.View(
1529 tc.db, func(tx walletdb.ReadTx) (e error) {
1530 ns := tx.ReadBucket(waddrmgrNamespaceKey)
1531 newName, e = tc.manager.AccountName(ns, tc.account)
1532 return e
1533 },
1534 )
1535 if e != nil {
1536 tc.t.Errorf("AccountName: unexpected error: %v", e)
1537 return false
1538 }
1539 if newName != testName {
1540 tc.t.Errorf(
1541 "RenameAccount "+
1542 "account name mismatch -- got %s, "+
1543 "want %s", newName, testName,
1544 )
1545 return false
1546 }
1547 // Test duplicate account name error
1548 e = walletdb.Update(
1549 tc.db, func(tx walletdb.ReadWriteTx) (e error) {
1550 ns := tx.ReadWriteBucket(waddrmgrNamespaceKey)
1551 return tc.manager.RenameAccount(ns, tc.account, testName)
1552 },
1553 )
1554 wantErrCode := waddrmgr.ErrDuplicateAccount
1555 if !checkManagerError(tc.t, testName, e, wantErrCode) {
1556 return false
1557 }
1558 // Test old account name is no longer valid
1559 e = walletdb.View(
1560 tc.db, func(tx walletdb.ReadTx) (e error) {
1561 ns := tx.ReadBucket(waddrmgrNamespaceKey)
1562 _, e = tc.manager.LookupAccount(ns, acctName)
1563 return e
1564 },
1565 )
1566 wantErrCode = waddrmgr.ErrAccountNotFound
1567 if !checkManagerError(tc.t, testName, e, wantErrCode) {
1568 return false
1569 }
1570 return true
1571 }
1572 1573 // testForEachAccount tests the retrieve all accounts func of the address
1574 // manager works as expected.
1575 func testForEachAccount(tc *testContext) bool {
1576 prefix := testNamePrefix(tc) + " testForEachAccount"
1577 expectedAccounts := []uint32{0, 1}
1578 if !tc.create {
1579 // Existing wallet manager will have 3 accounts
1580 expectedAccounts = append(expectedAccounts, 2)
1581 }
1582 // Imported account
1583 expectedAccounts = append(expectedAccounts, waddrmgr.ImportedAddrAccount)
1584 var accounts []uint32
1585 e := walletdb.View(
1586 tc.db, func(tx walletdb.ReadTx) (e error) {
1587 ns := tx.ReadBucket(waddrmgrNamespaceKey)
1588 return tc.manager.ForEachAccount(
1589 ns, func(account uint32) (e error) {
1590 accounts = append(accounts, account)
1591 return nil
1592 },
1593 )
1594 },
1595 )
1596 if e != nil {
1597 tc.t.Errorf("%s: unexpected error: %v", prefix, e)
1598 return false
1599 }
1600 if len(accounts) != len(expectedAccounts) {
1601 tc.t.Errorf(
1602 "%s: unexpected number of accounts - got "+
1603 "%d, want %d", prefix, len(accounts),
1604 len(expectedAccounts),
1605 )
1606 return false
1607 }
1608 for i, account := range accounts {
1609 if expectedAccounts[i] != account {
1610 tc.t.Errorf(
1611 "%s #%d: "+
1612 "account mismatch -- got %d, "+
1613 "want %d", prefix, i, account, expectedAccounts[i],
1614 )
1615 }
1616 }
1617 return true
1618 }
1619 1620 // testForEachAccountAddress tests that iterating through the given account
1621 // addresses using the manager API works as expected.
1622 func testForEachAccountAddress(tc *testContext) bool {
1623 prefix := testNamePrefix(tc) + " testForEachAccountAddress"
1624 // Make a map of expected addresses
1625 expectedAddrMap := make(map[string]*expectedAddr, len(expectedAddrs))
1626 for i := 0; i < len(expectedAddrs); i++ {
1627 expectedAddrMap[expectedAddrs[i].address] = &expectedAddrs[i]
1628 }
1629 var addrs []waddrmgr.ManagedAddress
1630 e := walletdb.View(
1631 tc.db, func(tx walletdb.ReadTx) (e error) {
1632 ns := tx.ReadBucket(waddrmgrNamespaceKey)
1633 return tc.manager.ForEachAccountAddress(
1634 ns, tc.account,
1635 func(maddr waddrmgr.ManagedAddress) (e error) {
1636 addrs = append(addrs, maddr)
1637 return nil
1638 },
1639 )
1640 },
1641 )
1642 if e != nil {
1643 tc.t.Errorf("%s: unexpected error: %v", prefix, e)
1644 return false
1645 }
1646 for i := 0; i < len(addrs); i++ {
1647 prefix = fmt.Sprintf("%s: #%d", prefix, i)
1648 gotAddr := addrs[i]
1649 wantAddr := expectedAddrMap[gotAddr.Address().String()]
1650 if !testAddress(tc, prefix, gotAddr, wantAddr) {
1651 return false
1652 }
1653 delete(expectedAddrMap, gotAddr.Address().String())
1654 }
1655 if len(expectedAddrMap) != 0 {
1656 tc.t.Errorf(
1657 "%s: unexpected addresses -- got %d, want %d", prefix,
1658 len(expectedAddrMap), 0,
1659 )
1660 return false
1661 }
1662 return true
1663 }
1664 1665 // testManagerAPI tests the functions provided by the Manager API as well as the
1666 // ManagedAddress, ManagedPubKeyAddress, and ManagedScriptAddress interfaces.
1667 func testManagerAPI(tc *testContext) {
1668 testLocking(tc)
1669 testExternalAddresses(tc)
1670 testInternalAddresses(tc)
1671 testImportPrivateKey(tc)
1672 testImportScript(tc)
1673 testMarkUsed(tc)
1674 testChangePassphrase(tc)
1675 // Reset default account
1676 tc.account = 0
1677 testNewAccount(tc)
1678 testLookupAccount(tc)
1679 testForEachAccount(tc)
1680 testForEachAccountAddress(tc)
1681 // Rename account 1 "acct-create"
1682 tc.account = 1
1683 testRenameAccount(tc)
1684 }
1685 1686 // testWatchingOnly tests various facets of a watching-only address manager such
1687 // as running the full set of API tests against a newly converted copy as well
1688 // as when it is opened from an existing namespace.
1689 func testWatchingOnly(tc *testContext) bool {
1690 // Make a copy of the current database so the copy can be converted to watching
1691 // only.
1692 woMgrName := "mgrtestwo.bin"
1693 _ = os.Remove(woMgrName)
1694 fi, e := os.OpenFile(woMgrName, os.O_CREATE|os.O_RDWR, 0600)
1695 if e != nil {
1696 tc.t.Errorf("%v", e)
1697 return false
1698 }
1699 if e = tc.db.Copy(fi); E.Chk(e) {
1700 if e = fi.Close(); waddrmgr.E.Chk(e) {
1701 }
1702 tc.t.Errorf("%v", e)
1703 return false
1704 }
1705 if e = fi.Close(); waddrmgr.E.Chk(e) {
1706 }
1707 defer func() {
1708 if e = os.Remove(woMgrName); waddrmgr.E.Chk(e) {
1709 }
1710 }()
1711 // Open the new database copy and get the address manager namespace.
1712 var db walletdb.DB
1713 if db, e = walletdb.Open("bdb", woMgrName); waddrmgr.E.Chk(e) {
1714 tc.t.Errorf("openDbNamespace: unexpected error: %v", e)
1715 return false
1716 }
1717 1718 defer func() {
1719 if e = db.Close(); waddrmgr.E.Chk(e) {
1720 }
1721 }()
1722 // Open the manager using the namespace and convert it to watching-only.
1723 var mgr *waddrmgr.Manager
1724 e = walletdb.View(
1725 db, func(tx walletdb.ReadTx) (e error) {
1726 ns := tx.ReadBucket(waddrmgrNamespaceKey)
1727 mgr, e = waddrmgr.Open(ns, pubPassphrase, &chaincfg.MainNetParams)
1728 return e
1729 },
1730 )
1731 if e != nil {
1732 tc.t.Errorf("%v", e)
1733 return false
1734 }
1735 e = walletdb.Update(
1736 db, func(tx walletdb.ReadWriteTx) (e error) {
1737 ns := tx.ReadWriteBucket(waddrmgrNamespaceKey)
1738 return mgr.ConvertToWatchingOnly(ns)
1739 },
1740 )
1741 if e != nil {
1742 tc.t.Errorf("%v", e)
1743 return false
1744 }
1745 // Run all of the manager API tests against the converted manager and close it.
1746 // We'll also retrieve the default scope (BIP0044) from the manager in order to
1747 // use.
1748 scopedMgr, e := mgr.FetchScopedKeyManager(waddrmgr.KeyScopeBIP0044)
1749 if e != nil {
1750 tc.t.Errorf("unable to fetch bip 44 scope %v", e)
1751 return false
1752 }
1753 testManagerAPI(
1754 &testContext{
1755 t: tc.t,
1756 db: db,
1757 rootManager: mgr,
1758 manager: scopedMgr,
1759 account: 0,
1760 create: false,
1761 watchingOnly: true,
1762 },
1763 )
1764 mgr.Close()
1765 // Open the watching-only manager and run all the tests again.
1766 e = walletdb.View(
1767 db, func(tx walletdb.ReadTx) (e error) {
1768 ns := tx.ReadBucket(waddrmgrNamespaceKey)
1769 mgr, e = waddrmgr.Open(ns, pubPassphrase, &chaincfg.MainNetParams)
1770 return e
1771 },
1772 )
1773 if e != nil {
1774 tc.t.Errorf("Open Watching-Only: unexpected error: %v", e)
1775 return false
1776 }
1777 defer mgr.Close()
1778 scopedMgr, e = mgr.FetchScopedKeyManager(waddrmgr.KeyScopeBIP0044)
1779 if e != nil {
1780 tc.t.Errorf("unable to fetch bip 44 scope %v", e)
1781 return false
1782 }
1783 testManagerAPI(
1784 &testContext{
1785 t: tc.t,
1786 db: db,
1787 rootManager: mgr,
1788 manager: scopedMgr,
1789 account: 0,
1790 create: false,
1791 watchingOnly: true,
1792 },
1793 )
1794 return true
1795 }
1796 1797 // testSync tests various facets of setting the manager sync state.
1798 func testSync(tc *testContext) bool {
1799 // Ensure syncing the manager to nil results in the synced to state being the
1800 // earliest block (genesis block in this case).
1801 e := walletdb.Update(
1802 tc.db, func(tx walletdb.ReadWriteTx) (e error) {
1803 ns := tx.ReadWriteBucket(waddrmgrNamespaceKey)
1804 return tc.rootManager.SetSyncedTo(ns, nil)
1805 },
1806 )
1807 if e != nil {
1808 tc.t.Errorf("SetSyncedTo unexpected e on nil: %v", e)
1809 return false
1810 }
1811 blockStamp := waddrmgr.BlockStamp{
1812 Height: 0,
1813 Hash: *chaincfg.MainNetParams.GenesisHash,
1814 }
1815 gotBlockStamp := tc.rootManager.SyncedTo()
1816 if gotBlockStamp != blockStamp {
1817 tc.t.Errorf(
1818 "SyncedTo unexpected block stamp on nil -- "+
1819 "got %v, want %v", gotBlockStamp, blockStamp,
1820 )
1821 return false
1822 }
1823 // If we update to a new more recent block time stamp, then upon retrieval it
1824 // should be returned as the best known state.
1825 latestHash, e := chainhash.NewHash(seed)
1826 if e != nil {
1827 tc.t.Errorf("%v", e)
1828 return false
1829 }
1830 blockStamp = waddrmgr.BlockStamp{
1831 Height: 1,
1832 Hash: *latestHash,
1833 Timestamp: time.Unix(1234, 0),
1834 }
1835 e = walletdb.Update(
1836 tc.db, func(tx walletdb.ReadWriteTx) (e error) {
1837 ns := tx.ReadWriteBucket(waddrmgrNamespaceKey)
1838 return tc.rootManager.SetSyncedTo(ns, &blockStamp)
1839 },
1840 )
1841 if e != nil {
1842 tc.t.Errorf("SetSyncedTo unexpected e on nil: %v", e)
1843 return false
1844 }
1845 gotBlockStamp = tc.rootManager.SyncedTo()
1846 if gotBlockStamp != blockStamp {
1847 tc.t.Errorf(
1848 "SyncedTo unexpected block stamp on nil -- "+
1849 "got %v, want %v", gotBlockStamp, blockStamp,
1850 )
1851 return false
1852 }
1853 return true
1854 }
1855 1856 // // TestManager performs a full suite of tests against the address manager API.
1857 // // It makes use of a test context because the address manager is persistent and
1858 // // much of the testing involves having specific state.
1859 // func TestManager(// t *testing.T) {
1860 // t.Parallel()
1861 // teardown, db := emptyDB(t)
1862 // defer teardown()
1863 // // Open manager that does not exist to ensure the expected error is
1864 // // returned.
1865 // e := walletdb.View(db, func(tx walletdb.ReadTx) (e error) {
1866 // ns := tx.ReadBucket(waddrmgrNamespaceKey)
1867 // _, e := waddrmgr.Open(ns, pubPassphrase, &chaincfg.MainNetParams)
1868 // return e
1869 // })
1870 // if !checkManagerError(t, "Open non-existent", e, waddrmgr.ErrNoExist) {
1871 // return
1872 // }
1873 // // Create a new manager.
1874 // var mgr *waddrmgr.Manager
1875 // e = walletdb.Update(db, func(tx walletdb.ReadWriteTx) (e error) {
1876 // ns, e := tx.CreateTopLevelBucket(waddrmgrNamespaceKey)
1877 // if e != nil {
1878 // return e
1879 // }
1880 // e = waddrmgr.Create(
1881 // ns, seed, pubPassphrase, privPassphrase,
1882 // &chaincfg.MainNetParams, fastScrypt, time.Time{},
1883 // )
1884 // if e != nil {
1885 // return e
1886 // }
1887 // mgr, e = waddrmgr.Open(ns, pubPassphrase, &chaincfg.MainNetParams)
1888 // return e
1889 // })
1890 // if e != nil {
1891 // t.Errorf("Create/Open: unexpected error: %v", e)
1892 // return
1893 // }
1894 // // NOTE: Not using deferred close here since part of the tests is
1895 // // explicitly closing the manager and then opening the existing one.
1896 // // Attempt to create the manager again to ensure the expected error is
1897 // // returned.
1898 // e = walletdb.Update(db, func(tx walletdb.ReadWriteTx) (e error) {
1899 // ns := tx.ReadWriteBucket(waddrmgrNamespaceKey)
1900 // return waddrmgr.Create(ns, seed, pubPassphrase, privPassphrase,
1901 // &chaincfg.MainNetParams, fastScrypt, time.Time{})
1902 // })
1903 // if !checkManagerError(t, "Create existing", e, waddrmgr.ErrAlreadyExists) {
1904 // mgr.Close()
1905 // return
1906 // }
1907 // // Run all of the manager API tests in create mode and close the
1908 // // manager after they've completed
1909 // scopedMgr, e := mgr.FetchScopedKeyManager(waddrmgr.KeyScopeBIP0044)
1910 // if e != nil {
1911 // t.Fatalf("unable to fetch default scope: %v", e)
1912 // }
1913 // testManagerAPI(&testContext{
1914 // t: t,
1915 // db: db,
1916 // manager: scopedMgr,
1917 // rootManager: mgr,
1918 // account: 0,
1919 // create: true,
1920 // watchingOnly: false,
1921 // })
1922 // mgr.Close()
1923 // // Ensure the expected error is returned if the latest manager version
1924 // // constant is bumped without writing code to actually do the upgrade.
1925 // *waddrmgr.TstLatestMgrVersion++
1926 // e = walletdb.View(db, func(tx walletdb.ReadTx) (e error) {
1927 // ns := tx.ReadBucket(waddrmgrNamespaceKey)
1928 // _, e := waddrmgr.Open(ns, pubPassphrase, &chaincfg.MainNetParams)
1929 // return e
1930 // })
1931 // if !checkManagerError(t, "Upgrade needed", e, waddrmgr.ErrUpgrade) {
1932 // return
1933 // }
1934 // *waddrmgr.TstLatestMgrVersion--
1935 // // Open the manager and run all the tests again in open mode which
1936 // // avoids reinserting new addresses like the create mode tests do.
1937 // e = walletdb.View(db, func(tx walletdb.ReadTx) (e error) {
1938 // ns := tx.ReadBucket(waddrmgrNamespaceKey)
1939 // var e error
1940 // mgr, e = waddrmgr.Open(ns, pubPassphrase, &chaincfg.MainNetParams)
1941 // return e
1942 // })
1943 // if e != nil {
1944 // t.Errorf("Open: unexpected error: %v", e)
1945 // return
1946 // }
1947 // defer mgr.Close()
1948 // scopedMgr, e = mgr.FetchScopedKeyManager(waddrmgr.KeyScopeBIP0044)
1949 // if e != nil {
1950 // t.Fatalf("unable to fetch default scope: %v", e)
1951 // }
1952 // tc := &testContext{
1953 // t: t,
1954 // db: db,
1955 // manager: scopedMgr,
1956 // rootManager: mgr,
1957 // account: 0,
1958 // create: false,
1959 // watchingOnly: false,
1960 // }
1961 // testManagerAPI(tc)
1962 // // Now that the address manager has been tested in both the newly
1963 // // created and opened modes, test a watching-only version.
1964 // testWatchingOnly(tc)
1965 // // Ensure that the manager sync state functionality works as expected.
1966 // testSync(tc)
1967 // // Unlock the manager so it can be closed with it unlocked to ensure
1968 // // it works without issue.
1969 // e = walletdb.View(db, func(tx walletdb.ReadTx) (e error) {
1970 // ns := tx.ReadBucket(waddrmgrNamespaceKey)
1971 // return mgr.Unlock(ns, privPassphrase)
1972 // })
1973 // if e != nil {
1974 // t.Errorf("Unlock: unexpected error: %v", e)
1975 // }
1976 // }
1977 1978 // TestEncryptDecryptErrors ensures that errors which occur while encrypting and
1979 // decrypting data return the expected errors.
1980 func TestEncryptDecryptErrors(t *testing.T) {
1981 t.Parallel()
1982 teardown, db, mgr := setupManager(t)
1983 defer teardown()
1984 invalidKeyType := waddrmgr.CryptoKeyType(0xff)
1985 var e error
1986 if _, e = mgr.Encrypt(invalidKeyType, []byte{}); e == nil {
1987 t.Fatalf("Encrypt accepted an invalid key type!")
1988 }
1989 if _, e = mgr.Decrypt(invalidKeyType, []byte{}); e == nil {
1990 t.Fatalf("Encrypt accepted an invalid key type!")
1991 }
1992 if !mgr.IsLocked() {
1993 t.Fatal("Manager should be locked at this point.")
1994 }
1995 // Now the mgr is locked and encrypting/decrypting with private keys should fail.
1996 _, e = mgr.Encrypt(waddrmgr.CKTPrivate, []byte{})
1997 checkManagerError(
1998 t, "encryption with private key fails when manager is locked",
1999 e, waddrmgr.ErrLocked,
2000 )
2001 _, e = mgr.Decrypt(waddrmgr.CKTPrivate, []byte{})
2002 checkManagerError(
2003 t, "decryption with private key fails when manager is locked",
2004 e, waddrmgr.ErrLocked,
2005 )
2006 // Unlock the manager for these tests
2007 e = walletdb.View(
2008 db, func(tx walletdb.ReadTx) (e error) {
2009 ns := tx.ReadBucket(waddrmgrNamespaceKey)
2010 return mgr.Unlock(ns, privPassphrase)
2011 },
2012 )
2013 if e != nil {
2014 t.Fatal("Attempted to unlock the manager, but failed:", e)
2015 }
2016 // Make sure to cover the ErrCrypto error path in Encrypt.
2017 waddrmgr.TstRunWithFailingCryptoKeyPriv(
2018 mgr, func() {
2019 _, e = mgr.Encrypt(waddrmgr.CKTPrivate, []byte{})
2020 },
2021 )
2022 checkManagerError(t, "failed encryption", e, waddrmgr.ErrCrypto)
2023 // Make sure to cover the ErrCrypto error path in Decrypt.
2024 waddrmgr.TstRunWithFailingCryptoKeyPriv(
2025 mgr, func() {
2026 _, e = mgr.Decrypt(waddrmgr.CKTPrivate, []byte{})
2027 },
2028 )
2029 checkManagerError(t, "failed decryption", e, waddrmgr.ErrCrypto)
2030 }
2031 2032 // TestEncryptDecrypt ensures that encrypting and decrypting data with the the
2033 // various crypto key types works as expected.
2034 func TestEncryptDecrypt(t *testing.T) {
2035 t.Parallel()
2036 teardown, db, mgr := setupManager(t)
2037 defer teardown()
2038 plainText := []byte("this is a plaintext")
2039 // Make sure address manager is unlocked
2040 e := walletdb.View(
2041 db, func(tx walletdb.ReadTx) (e error) {
2042 ns := tx.ReadBucket(waddrmgrNamespaceKey)
2043 return mgr.Unlock(ns, privPassphrase)
2044 },
2045 )
2046 if e != nil {
2047 t.Fatal("Attempted to unlock the manager, but failed:", e)
2048 }
2049 keyTypes := []waddrmgr.CryptoKeyType{
2050 waddrmgr.CKTPublic,
2051 waddrmgr.CKTPrivate,
2052 waddrmgr.CKTScript,
2053 }
2054 for _, keyType := range keyTypes {
2055 cipherText, e := mgr.Encrypt(keyType, plainText)
2056 if e != nil {
2057 t.Fatalf("Failed to encrypt plaintext: %v", e)
2058 }
2059 decryptedCipherText, e := mgr.Decrypt(keyType, cipherText)
2060 if e != nil {
2061 t.Fatalf("Failed to decrypt plaintext: %v", e)
2062 }
2063 if !reflect.DeepEqual(decryptedCipherText, plainText) {
2064 t.Fatal("Got:", decryptedCipherText, ", want:", plainText)
2065 }
2066 }
2067 }
2068 2069 // // TestScopedKeyManagerManagement tests that callers are able to properly
2070 // // create, retrieve, and utilize new scoped managers outside the set of default
2071 // // created scopes.
2072 // func TestScopedKeyManagerManagement(t *testing.T) {
2073 // t.Parallel()
2074 // teardown, db := emptyDB(t)
2075 // defer teardown()
2076 // // We'll start the test by creating a new root manager that will be used for the
2077 // // duration of the test.
2078 // var mgr *waddrmgr.Manager
2079 // e := walletdb.Update(
2080 // db, func(tx walletdb.ReadWriteTx) (e error) {
2081 // ns, e := tx.CreateTopLevelBucket(waddrmgrNamespaceKey)
2082 // if e != nil {
2083 // return e
2084 // }
2085 // e = waddrmgr.Create(
2086 // ns, seed, pubPassphrase, privPassphrase,
2087 // &chaincfg.MainNetParams, fastScrypt, time.Time{},
2088 // )
2089 // if e != nil {
2090 // return e
2091 // }
2092 // mgr, e = waddrmgr.Open(
2093 // ns, pubPassphrase, &chaincfg.MainNetParams,
2094 // )
2095 // if e != nil {
2096 // return e
2097 // }
2098 // return mgr.Unlock(ns, privPassphrase)
2099 // },
2100 // )
2101 // if e != nil {
2102 // t.Fatalf("create/open: unexpected error: %v", e)
2103 // }
2104 // // All the default scopes should have been created and loaded into memory upon
2105 // // initial opening.
2106 // for _, scope := range waddrmgr.DefaultKeyScopes {
2107 // _, e := mgr.FetchScopedKeyManager(scope)
2108 // if e != nil {
2109 // t.Fatalf("unable to fetch scope %v: %v", scope, e)
2110 // }
2111 // }
2112 // // Next, ensure that if we create an internal and external addrs for each of the
2113 // // default scope types, then they're derived according to their schema.
2114 // e = walletdb.Update(
2115 // db, func(tx walletdb.ReadWriteTx) (e error) {
2116 // ns := tx.ReadWriteBucket(waddrmgrNamespaceKey)
2117 // for _, scope := range waddrmgr.DefaultKeyScopes {
2118 // sMgr, e := mgr.FetchScopedKeyManager(scope)
2119 // if e != nil {
2120 // t.Fatalf("unable to fetch scope %v: %v", scope, e)
2121 // }
2122 // externalAddr, e := sMgr.NextExternalAddresses(
2123 // ns, waddrmgr.DefaultAccountNum, 1,
2124 // )
2125 // if e != nil {
2126 // t.Fatalf("unable to derive external addr: %v", e)
2127 // }
2128 // // The external address should match the prescribed addr schema for this scoped
2129 // // key manager.
2130 // if externalAddr[0].AddrType() != waddrmgr.ScopeAddrMap[scope].ExternalAddrType {
2131 // t.Fatalf(
2132 // "addr type mismatch: expected %v, got %v",
2133 // externalAddr[0].AddrType(),
2134 // waddrmgr.ScopeAddrMap[scope].ExternalAddrType,
2135 // )
2136 // }
2137 // internalAddr, e := sMgr.NextInternalAddresses(
2138 // ns, waddrmgr.DefaultAccountNum, 1,
2139 // )
2140 // if e != nil {
2141 // t.Fatalf("unable to derive internal addr: %v", e)
2142 // }
2143 // // Similarly, the internal address should match the prescribed addr schema for
2144 // // this scoped key manager.
2145 // if internalAddr[0].AddrType() != waddrmgr.ScopeAddrMap[scope].InternalAddrType {
2146 // t.Fatalf(
2147 // "addr type mismatch: expected %v, got %v",
2148 // internalAddr[0].AddrType(),
2149 // waddrmgr.ScopeAddrMap[scope].InternalAddrType,
2150 // )
2151 // }
2152 // }
2153 // return e
2154 // },
2155 // )
2156 // if e != nil {
2157 // t.Fatalf("unable to read db: %v", e)
2158 // }
2159 // // Now that the manager is open, we'll create a "test" scope that we'll be
2160 // // utilizing for the remainder of the test.
2161 // testScope := waddrmgr.KeyScope{
2162 // Purpose: 99,
2163 // Coin: 0,
2164 // }
2165 // addrSchema := waddrmgr.ScopeAddrSchema{
2166 // ExternalAddrType: waddrmgr.NestedWitnessPubKey,
2167 // InternalAddrType: waddrmgr.WitnessPubKey,
2168 // }
2169 // var scopedMgr *waddrmgr.ScopedKeyManager
2170 // e = walletdb.Update(
2171 // db, func(tx walletdb.ReadWriteTx) (e error) {
2172 // ns := tx.ReadWriteBucket(waddrmgrNamespaceKey)
2173 // scopedMgr, e = mgr.NewScopedKeyManager(ns, testScope, addrSchema)
2174 // if e != nil {
2175 // return e
2176 // }
2177 // return nil
2178 // },
2179 // )
2180 // if e != nil {
2181 // t.Fatalf("unable to read db: %v", e)
2182 // }
2183 // // The manager was just created, we should be able to look it up within the root
2184 // // manager.
2185 // if _, e = mgr.FetchScopedKeyManager(testScope); E.Chk(e) {
2186 // t.Fatalf("attempt to read created mgr failed: %v", e)
2187 // }
2188 // var externalAddr, internalAddr []waddrmgr.ManagedAddress
2189 // e = walletdb.Update(
2190 // db, func(tx walletdb.ReadWriteTx) (e error) {
2191 // ns := tx.ReadWriteBucket(waddrmgrNamespaceKey)
2192 // // We'll now create a new external address to ensure we retrieve the proper
2193 // // type.
2194 // externalAddr, e = scopedMgr.NextExternalAddresses(
2195 // ns, waddrmgr.DefaultAccountNum, 1,
2196 // )
2197 // if e != nil {
2198 // t.Fatalf("unable to derive external addr: %v", e)
2199 // }
2200 // internalAddr, e = scopedMgr.NextInternalAddresses(
2201 // ns, waddrmgr.DefaultAccountNum, 1,
2202 // )
2203 // if e != nil {
2204 // t.Fatalf("unable to derive internal addr: %v", e)
2205 // }
2206 // return nil
2207 // },
2208 // )
2209 // if e != nil {
2210 // t.Fatalf("open: unexpected error: %v", e)
2211 // }
2212 // // Ensure that the type of the address matches as expected.
2213 // if externalAddr[0].AddrType() != waddrmgr.NestedWitnessPubKey {
2214 // t.Fatalf(
2215 // "addr type mismatch: expected %v, got %v",
2216 // waddrmgr.NestedWitnessPubKey, externalAddr[0].AddrType(),
2217 // )
2218 // }
2219 // _, ok := externalAddr[0].Address().(*util.ScriptHash)
2220 // if !ok {
2221 // t.Fatalf("wrong type: %T", externalAddr[0].Address())
2222 // }
2223 // // We'll also create an internal address and ensure that the types match up
2224 // // properly.
2225 // if internalAddr[0].AddrType() != waddrmgr.WitnessPubKey {
2226 // t.Fatalf(
2227 // "addr type mismatch: expected %v, got %v",
2228 // waddrmgr.WitnessPubKey, internalAddr[0].AddrType(),
2229 // )
2230 // }
2231 // _, ok = internalAddr[0].Address().(*util.AddressWitnessPubKeyHash)
2232 // if !ok {
2233 // t.Fatalf("wrong type: %T", externalAddr[0].Address())
2234 // }
2235 // // We'll now simulate a restart by closing, then restarting the manager.
2236 // mgr.Close()
2237 // e = walletdb.View(
2238 // db, func(tx walletdb.ReadTx) (e error) {
2239 // ns := tx.ReadBucket(waddrmgrNamespaceKey)
2240 // var e error
2241 // mgr, e = waddrmgr.Open(ns, pubPassphrase, &chaincfg.MainNetParams)
2242 // if e != nil {
2243 // return e
2244 // }
2245 // return mgr.Unlock(ns, privPassphrase)
2246 // },
2247 // )
2248 // if e != nil {
2249 // t.Fatalf("open: unexpected error: %v", e)
2250 // }
2251 // defer mgr.Close()
2252 // // We should be able to retrieve the new scoped manager that we just created.
2253 // scopedMgr, e = mgr.FetchScopedKeyManager(testScope)
2254 // if e != nil {
2255 // t.Fatalf("attempt to read created mgr failed: %v", e)
2256 // }
2257 // // If we fetch the last generated external address, it should map exactly to the
2258 // // address that we just generated.
2259 // var lastAddr waddrmgr.ManagedAddress
2260 // e = walletdb.Update(
2261 // db, func(tx walletdb.ReadWriteTx) (e error) {
2262 // ns := tx.ReadWriteBucket(waddrmgrNamespaceKey)
2263 // lastAddr, e = scopedMgr.LastExternalAddress(
2264 // ns, waddrmgr.DefaultAccountNum,
2265 // )
2266 // if e != nil {
2267 // return e
2268 // }
2269 // return nil
2270 // },
2271 // )
2272 // if e != nil {
2273 // t.Fatalf("open: unexpected error: %v", e)
2274 // }
2275 // if !bytes.Equal(lastAddr.AddrHash(), externalAddr[0].AddrHash()) {
2276 // t.Fatalf(
2277 // "mismatch addr hashes: expected %x, got %x",
2278 // externalAddr[0].AddrHash(), lastAddr.AddrHash(),
2279 // )
2280 // }
2281 // // After the restart, all the default scopes should be been re-loaded.
2282 // for _, scope := range waddrmgr.DefaultKeyScopes {
2283 // _, e := mgr.FetchScopedKeyManager(scope)
2284 // if e != nil {
2285 // t.Fatalf("unable to fetch scope %v: %v", scope, e)
2286 // }
2287 // }
2288 // // Finally, if we attempt to query the root manager for this last address, it
2289 // // should be able to locate the private key, etc.
2290 // e = walletdb.Update(
2291 // db, func(tx walletdb.ReadWriteTx) (e error) {
2292 // ns := tx.ReadWriteBucket(waddrmgrNamespaceKey)
2293 // _, e := mgr.Address(ns, lastAddr.Address())
2294 // if e != nil {
2295 // return fmt.Errorf("unable to find addr: %v", e)
2296 // }
2297 // e = mgr.MarkUsed(ns, lastAddr.Address())
2298 // if e != nil {
2299 // return fmt.Errorf(
2300 // "unable to mark addr as "+
2301 // "used: %v", e,
2302 // )
2303 // }
2304 // return nil
2305 // },
2306 // )
2307 // if e != nil {
2308 // t.Fatalf("unable to find addr: %v", e)
2309 // }
2310 // }
2311 2312 // // TestRootHDKeyNeutering tests that callers are unable to create new scoped
2313 // // managers once the root HD key has been deleted from the database.
2314 // func TestRootHDKeyNeutering(t *testing.T) {
2315 // t.Parallel()
2316 // teardown, db := emptyDB(t)
2317 // defer teardown()
2318 // // We'll start the test by creating a new root manager that will be used for the
2319 // // duration of the test.
2320 // var mgr *waddrmgr.Manager
2321 // e := walletdb.Update(
2322 // db, func(tx walletdb.ReadWriteTx) (e error) {
2323 // ns, e := tx.CreateTopLevelBucket(waddrmgrNamespaceKey)
2324 // if e != nil {
2325 // return e
2326 // }
2327 // e = waddrmgr.Create(
2328 // ns, seed, pubPassphrase, privPassphrase,
2329 // &chaincfg.MainNetParams, fastScrypt, time.Time{},
2330 // )
2331 // if e != nil {
2332 // return e
2333 // }
2334 // mgr, e = waddrmgr.Open(
2335 // ns, pubPassphrase, &chaincfg.MainNetParams,
2336 // )
2337 // if e != nil {
2338 // return e
2339 // }
2340 // return mgr.Unlock(ns, privPassphrase)
2341 // },
2342 // )
2343 // if e != nil {
2344 // t.Fatalf("create/open: unexpected error: %v", e)
2345 // }
2346 // defer mgr.Close()
2347 // // With the root manager open, we'll now create a new scoped manager for usage
2348 // // within this test.
2349 // testScope := waddrmgr.KeyScope{
2350 // Purpose: 99,
2351 // Coin: 0,
2352 // }
2353 // addrSchema := waddrmgr.ScopeAddrSchema{
2354 // ExternalAddrType: waddrmgr.NestedWitnessPubKey,
2355 // InternalAddrType: waddrmgr.WitnessPubKey,
2356 // }
2357 // e = walletdb.Update(
2358 // db, func(tx walletdb.ReadWriteTx) (e error) {
2359 // ns := tx.ReadWriteBucket(waddrmgrNamespaceKey)
2360 // _, e := mgr.NewScopedKeyManager(ns, testScope, addrSchema)
2361 // if e != nil {
2362 // return e
2363 // }
2364 // return nil
2365 // },
2366 // )
2367 // if e != nil {
2368 // t.Fatalf("unable to read db: %v", e)
2369 // }
2370 // // With the manager created, we'll now neuter the root HD private key.
2371 // e = walletdb.Update(
2372 // db, func(tx walletdb.ReadWriteTx) (e error) {
2373 // ns := tx.ReadWriteBucket(waddrmgrNamespaceKey)
2374 // return mgr.NeuterRootKey(ns)
2375 // },
2376 // )
2377 // if e != nil {
2378 // t.Fatalf("unable to read db: %v", e)
2379 // }
2380 // // If we try to create *another* scope, this should fail, as the root key is no
2381 // // longer in the database.
2382 // testScope = waddrmgr.KeyScope{
2383 // Purpose: 100,
2384 // Coin: 0,
2385 // }
2386 // e = walletdb.Update(
2387 // db, func(tx walletdb.ReadWriteTx) (e error) {
2388 // ns := tx.ReadWriteBucket(waddrmgrNamespaceKey)
2389 // _, e := mgr.NewScopedKeyManager(ns, testScope, addrSchema)
2390 // if e != nil {
2391 // return e
2392 // }
2393 // return nil
2394 // },
2395 // )
2396 // if e == nil {
2397 // t.Fatalf("new scoped manager creation should have failed")
2398 // }
2399 // }
2400 2401 // // TestNewRawAccount tests that callers are able to properly create, and use raw
2402 // // accounts created with only an account number, and not a string which is
2403 // // eventually mapped to an account number.
2404 // func TestNewRawAccount(t *testing.T) {
2405 // t.Parallel()
2406 // teardown, db := emptyDB(t)
2407 // defer teardown()
2408 // // We'll start the test by creating a new root manager that will be used for the
2409 // // duration of the test.
2410 // var mgr *waddrmgr.Manager
2411 // e := walletdb.Update(
2412 // db, func(tx walletdb.ReadWriteTx) (e error) {
2413 // ns, e := tx.CreateTopLevelBucket(waddrmgrNamespaceKey)
2414 // if e != nil {
2415 // return e
2416 // }
2417 // e = waddrmgr.Create(
2418 // ns, seed, pubPassphrase, privPassphrase,
2419 // &chaincfg.MainNetParams, fastScrypt, time.Time{},
2420 // )
2421 // if e != nil {
2422 // return e
2423 // }
2424 // mgr, e = waddrmgr.Open(
2425 // ns, pubPassphrase, &chaincfg.MainNetParams,
2426 // )
2427 // if e != nil {
2428 // return e
2429 // }
2430 // return mgr.Unlock(ns, privPassphrase)
2431 // },
2432 // )
2433 // if e != nil {
2434 // t.Fatalf("create/open: unexpected error: %v", e)
2435 // }
2436 // defer mgr.Close()
2437 // // Now that we have the manager created, we'll fetch one of the default scopes
2438 // // for usage within this test.
2439 // scopedMgr, e := mgr.FetchScopedKeyManager(waddrmgr.KeyScopeBIP0084)
2440 // if e != nil {
2441 // t.Fatalf("unable to fetch scope %v: %v", waddrmgr.KeyScopeBIP0084, e)
2442 // }
2443 // // With the scoped manager retrieved, we'll attempt to create a new raw account
2444 // // by number.
2445 // const accountNum = 1000
2446 // e = walletdb.Update(
2447 // db, func(tx walletdb.ReadWriteTx) (e error) {
2448 // ns := tx.ReadWriteBucket(waddrmgrNamespaceKey)
2449 // return scopedMgr.NewRawAccount(ns, accountNum)
2450 // },
2451 // )
2452 // if e != nil {
2453 // t.Fatalf("unable to create new account: %v", e)
2454 // }
2455 // // With the account created, we should be able to derive new addresses from the
2456 // // account.
2457 // var accountAddrNext waddrmgr.ManagedAddress
2458 // e = walletdb.Update(
2459 // db, func(tx walletdb.ReadWriteTx) (e error) {
2460 // ns := tx.ReadWriteBucket(waddrmgrNamespaceKey)
2461 // addrs, e := scopedMgr.NextExternalAddresses(
2462 // ns, accountNum, 1,
2463 // )
2464 // if e != nil {
2465 // return e
2466 // }
2467 // accountAddrNext = addrs[0]
2468 // return nil
2469 // },
2470 // )
2471 // if e != nil {
2472 // t.Fatalf("unable to create addr: %v", e)
2473 // }
2474 // // Additionally, we should be able to manually derive specific target keys.
2475 // var accountTargetAddr waddrmgr.ManagedAddress
2476 // e = walletdb.Update(
2477 // db, func(tx walletdb.ReadWriteTx) (e error) {
2478 // ns := tx.ReadWriteBucket(waddrmgrNamespaceKey)
2479 // keyPath := waddrmgr.DerivationPath{
2480 // Account: accountNum,
2481 // Branch: 0,
2482 // Index: 0,
2483 // }
2484 // accountTargetAddr, e = scopedMgr.DeriveFromKeyPath(
2485 // ns, keyPath,
2486 // )
2487 // return e
2488 // },
2489 // )
2490 // if e != nil {
2491 // t.Fatalf("unable to derive addr: %v", e)
2492 // }
2493 // // The two keys we just derived should match up perfectly.
2494 // if accountAddrNext.AddrType() != accountTargetAddr.AddrType() {
2495 // t.Fatalf(
2496 // "wrong addr type: %v vs %v",
2497 // accountAddrNext.AddrType(), accountTargetAddr.AddrType(),
2498 // )
2499 // }
2500 // if !bytes.Equal(accountAddrNext.AddrHash(), accountTargetAddr.AddrHash()) {
2501 // t.Fatalf(
2502 // "wrong pubkey hash: %x vs %x", accountAddrNext.AddrHash(),
2503 // accountTargetAddr.AddrHash(),
2504 // )
2505 // }
2506 // }
2507