github.com/decred/dcrlnd@v0.7.6/lnwallet/remotedcrwallet/keychain.go (about)

     1  package remotedcrwallet
     2  
     3  import (
     4  	"errors"
     5  
     6  	"github.com/decred/dcrd/hdkeychain/v3"
     7  	"github.com/decred/dcrd/txscript/v4/stdaddr"
     8  	"github.com/decred/dcrlnd/channeldb"
     9  	"github.com/decred/dcrlnd/keychain"
    10  	"github.com/decred/dcrlnd/lnwallet"
    11  )
    12  
    13  // onchainAddrSourcer is an interface for the required operations needed to
    14  // derive keys that also correspond to regular onchain wallet addresses.
    15  type onchainAddrSourcer interface {
    16  	// NewAddress must return the next usable onchain address for the
    17  	// wallet.
    18  	NewAddress(t lnwallet.AddressType, change bool, accountName string) (stdaddr.Address, error)
    19  
    20  	// Bip44AddressInfo returns the respective account, branch and index
    21  	// for the given wallet address.
    22  	Bip44AddressInfo(addr stdaddr.Address) (uint32, uint32, uint32, error)
    23  }
    24  
    25  // remoteWalletKeyRing is an implementation of both the KeyRing and
    26  // SecretKeyRing interfaces backed by a root master HD key.
    27  type remoteWalletKeyRing struct {
    28  	*keychain.HDKeyRing
    29  
    30  	onchainAddrs onchainAddrSourcer
    31  
    32  	rootXPriv          *hdkeychain.ExtendedKey
    33  	multiSigKFXpriv    *hdkeychain.ExtendedKey
    34  	paymentBaseKFXpriv *hdkeychain.ExtendedKey
    35  
    36  	// db is a pointer to a channeldb.DB instance that stores the indices
    37  	// of used keys of the keyring. This is used to track the next
    38  	// available key to prevent key reuse when establishing channels.
    39  	db *channeldb.DB
    40  }
    41  
    42  // Compile time type assertions to ensure remoteWalletKeyRing fulfills the desired
    43  // interfaces.
    44  var _ keychain.KeyRing = (*remoteWalletKeyRing)(nil)
    45  var _ keychain.SecretKeyRing = (*remoteWalletKeyRing)(nil)
    46  
    47  // newRemoteWalletKeyRing creates a new implementation of the
    48  // keychain.SecretKeyRing interface backed by the given root extended private
    49  // key.
    50  func newRemoteWalletKeyRing(rootAccountXPriv *hdkeychain.ExtendedKey,
    51  	db *channeldb.DB, onchainAddrs onchainAddrSourcer) (*remoteWalletKeyRing, error) {
    52  
    53  	if !rootAccountXPriv.IsPrivate() {
    54  		return nil, errors.New("Provided key is not an extended private key")
    55  	}
    56  
    57  	// By convention, the root LN key is a hardened key derived from index
    58  	// 1017 of a wallet account.
    59  	idx := uint32(hdkeychain.HardenedKeyStart + keychain.BIP0043Purpose)
    60  	rootXPriv, err := rootAccountXPriv.Child(idx)
    61  	if err != nil {
    62  		return nil, err
    63  	}
    64  
    65  	// This assumes that there are no discontinuities within the KeyFamily
    66  	// constants.
    67  	lastKeyFam := uint32(keychain.KeyFamilyLastKF)
    68  	masterPubs := make(map[keychain.KeyFamily]*hdkeychain.ExtendedKey,
    69  		lastKeyFam+1)
    70  
    71  	// The masterpub for the multisig key family is still the external
    72  	// branch for the root account xpriv provided. This allows the wallet
    73  	// itself to watch for on-chain spends from it and correctly account
    74  	// for its funds.
    75  	multiSigXPriv, err := rootAccountXPriv.Child(0)
    76  	if err != nil {
    77  		return nil, err
    78  	}
    79  	multiSigXPub := multiSigXPriv.Neuter()
    80  	masterPubs[keychain.KeyFamilyMultiSig] = multiSigXPub
    81  
    82  	// The masterpub for the payment base key family (i.e. addresses used
    83  	// for our non-encumbered output in remote commitments) is the internal
    84  	// branch for the root account xpriv provided. This allows the wallet
    85  	// to directly spend these funds when a breach or DLP scenario is
    86  	// triggered without requiring any other off-chain state.
    87  	paymentBaseXPriv, err := rootAccountXPriv.Child(0)
    88  	if err != nil {
    89  		return nil, err
    90  	}
    91  	paymentBaseXPub := paymentBaseXPriv.Neuter()
    92  	masterPubs[keychain.KeyFamilyPaymentBase] = paymentBaseXPub
    93  
    94  	// Derive the master pubs for the other key families.
    95  	for i := uint32(0); i <= lastKeyFam; i++ {
    96  		switch keychain.KeyFamily(i) {
    97  		case keychain.KeyFamilyMultiSig:
    98  			continue
    99  		case keychain.KeyFamilyPaymentBase:
   100  			continue
   101  		}
   102  
   103  		// Errors here cause fatal failures due to the wallet not
   104  		// attempting to generate the next account.
   105  		famKey, err := rootXPriv.Child(hdkeychain.HardenedKeyStart + i)
   106  		if err != nil {
   107  			return nil, err
   108  		}
   109  
   110  		famPub := famKey.Neuter()
   111  		masterPubs[keychain.KeyFamily(i)] = famPub
   112  	}
   113  
   114  	wkr := &remoteWalletKeyRing{
   115  		rootXPriv:          rootXPriv,
   116  		multiSigKFXpriv:    multiSigXPriv,
   117  		paymentBaseKFXpriv: paymentBaseXPriv,
   118  		db:                 db,
   119  		onchainAddrs:       onchainAddrs,
   120  	}
   121  	wkr.HDKeyRing = keychain.NewHDKeyRing(masterPubs, wkr.fetchMasterPriv,
   122  		wkr.nextIndex)
   123  	return wkr, nil
   124  }
   125  
   126  func (kr *remoteWalletKeyRing) nextIndex(keyFam keychain.KeyFamily) (uint32, error) {
   127  	switch keyFam {
   128  	case keychain.KeyFamilyMultiSig,
   129  		keychain.KeyFamilyPaymentBase:
   130  
   131  		// For these key families, instead of using the channel
   132  		// database to track indices we request the next available
   133  		// address from the wallet (with the wrap gap policy) and
   134  		// decode its index.
   135  		//
   136  		// The net result is that the wallet should always be able to
   137  		// find these addresses and their respective keys during
   138  		// address discovery instead of requiring input from the
   139  		// lightning wallet.
   140  		branchInternal := keyFam == keychain.KeyFamilyPaymentBase
   141  		addr, err := kr.onchainAddrs.NewAddress(
   142  			lnwallet.PubKeyHash, branchInternal, lnwallet.DefaultAccountName,
   143  		)
   144  		if err != nil {
   145  			return 0, err
   146  		}
   147  
   148  		_, _, addrIndex, err := kr.onchainAddrs.Bip44AddressInfo(addr)
   149  		if err != nil {
   150  			return 0, err
   151  		}
   152  		return addrIndex, nil
   153  
   154  	}
   155  
   156  	return kr.db.NextKeyFamilyIndex(uint32(keyFam))
   157  }
   158  
   159  func (kr *remoteWalletKeyRing) fetchMasterPriv(keyFam keychain.KeyFamily) (*hdkeychain.ExtendedKey,
   160  	error) {
   161  
   162  	// The master priv of the special key families that correspond to
   163  	// regular on-chain branches are stored separately.
   164  	switch keyFam {
   165  	case keychain.KeyFamilyMultiSig:
   166  		return kr.multiSigKFXpriv, nil
   167  	case keychain.KeyFamilyPaymentBase:
   168  		return kr.paymentBaseKFXpriv, nil
   169  	}
   170  
   171  	// For the other keyfamilies, derive from the alternative root branch.
   172  	idx := uint32(hdkeychain.HardenedKeyStart + keyFam)
   173  	famKey, err := kr.rootXPriv.Child(idx)
   174  	if err != nil {
   175  		return nil, err
   176  	}
   177  
   178  	return famKey, nil
   179  }