github.com/decred/dcrlnd@v0.7.6/lnwallet/dcrwallet/keychain.go (about) 1 package dcrwallet 2 3 import ( 4 "context" 5 6 "github.com/decred/dcrlnd/channeldb" 7 "github.com/decred/dcrlnd/keychain" 8 9 "decred.org/dcrwallet/v4/wallet" 10 "decred.org/dcrwallet/v4/wallet/udb" 11 "github.com/decred/dcrd/hdkeychain/v3" 12 ) 13 14 // walletKeyRing is an implementation of both the KeyRing and SecretKeyRing 15 // interfaces backed by dcrwallet's internal root keys. 16 // 17 // While the wallet's root keys are used, the actual final key derivation does 18 // _not_ take place in the wallet; instead it is done here. This is done so 19 // that the wallet does not attempt to keep track of a large amount of keys 20 // (addresses) that are meant for off-chain processes and are unlikely to ever 21 // be found on-chain. 22 // 23 // Even though the final keys are derived here, they are currently derived 24 // following a BIP0043 style path starting at the first account (account number 25 // 0) and for the external branch only, which maintains compatibility with a 26 // previous version of this implementation that was done entirely on the 27 // wallet. Note that changing this derivation procedure means invalidating 28 // existing dcrlnd wallets. 29 type walletKeyRing struct { 30 *keychain.HDKeyRing 31 32 // wallet is a pointer to the active instance of the dcrwallet core. 33 // This is required as we'll need to manually open database 34 // transactions in order to derive addresses and lookup relevant keys 35 wallet *wallet.Wallet 36 37 // db is a pointer to a channeldb.DB instance that stores the indices 38 // of used keys of the keyring. This is used to track the next 39 // available key to prevent key reuse when establishing channels. 40 db *channeldb.DB 41 } 42 43 // Compile time type assertions to ensure walletKeyRing fulfills the desired 44 // interfaces. 45 var _ keychain.KeyRing = (*walletKeyRing)(nil) 46 var _ keychain.SecretKeyRing = (*walletKeyRing)(nil) 47 48 // creates a new implementation of the keychain.SecretKeyRing interface backed 49 // by dcrwallet. 50 // 51 // NOTE: The passed wallet MUST be unlocked in order for the keychain to 52 // function. 53 func newWalletKeyRing(w *wallet.Wallet, db *channeldb.DB) (*walletKeyRing, error) { 54 55 // This assumes that there are no discontinuities within the KeyFamily 56 // constants. 57 lastKeyFam := uint32(keychain.KeyFamilyLastKF) 58 masterPubs := make(map[keychain.KeyFamily]*hdkeychain.ExtendedKey, 59 lastKeyFam+1) 60 61 ctKey, err := w.CoinTypePrivKey(context.TODO()) 62 if err != nil { 63 return nil, err 64 } 65 66 // Derive the master pubs for each key family. They are mapped to the 67 // external branch for each corresponding wallet account. 68 for i := uint32(0); i <= lastKeyFam; i++ { 69 // Errors here cause fatal failures due to the wallet not 70 // attempting to generate the next account. 71 acctKey, err := ctKey.Child(hdkeychain.HardenedKeyStart + i) 72 if err != nil { 73 return nil, err 74 } 75 76 branchKey, err := acctKey.Child(udb.ExternalBranch) 77 if err != nil { 78 return nil, err 79 } 80 81 branchPub := branchKey.Neuter() 82 masterPubs[keychain.KeyFamily(i)] = branchPub 83 } 84 85 wkr := &walletKeyRing{ 86 wallet: w, 87 db: db, 88 } 89 wkr.HDKeyRing = keychain.NewHDKeyRing(masterPubs, wkr.fetchMasterPriv, 90 wkr.nextIndex) 91 return wkr, nil 92 } 93 94 func (wkr *walletKeyRing) nextIndex(keyFam keychain.KeyFamily) (uint32, error) { 95 return wkr.db.NextKeyFamilyIndex(uint32(keyFam)) 96 } 97 98 func (wkr *walletKeyRing) fetchMasterPriv(keyFam keychain.KeyFamily) (*hdkeychain.ExtendedKey, 99 error) { 100 101 ctKey, err := wkr.wallet.CoinTypePrivKey(context.TODO()) 102 if err != nil { 103 return nil, err 104 } 105 106 acctKey, err := ctKey.Child(hdkeychain.HardenedKeyStart + uint32(keyFam)) 107 if err != nil { 108 return nil, err 109 } 110 111 branchKey, err := acctKey.Child(udb.ExternalBranch) 112 if err != nil { 113 return nil, err 114 } 115 116 return branchKey, nil 117 }