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  }