From 93280ad60af9edde8a6b175b92543539c9429ce8 Mon Sep 17 00:00:00 2001 From: Olaoluwa Osuntokun Date: Sat, 17 Feb 2018 15:03:59 -0800 Subject: [PATCH] lnwallet/btcwallet: update implementation to account for recent API changes The new version of the internal core of btcwallet now uses KeyScopes rather than address types to derive particular addresses. As a result, in this commit, we update our API usage to ensure that proper addresses are still derived. --- lnwallet/btcwallet/btcwallet.go | 104 +++++++++++++++++++------------- 1 file changed, 61 insertions(+), 43 deletions(-) diff --git a/lnwallet/btcwallet/btcwallet.go b/lnwallet/btcwallet/btcwallet.go index b446974b..f9039ea7 100644 --- a/lnwallet/btcwallet/btcwallet.go +++ b/lnwallet/btcwallet/btcwallet.go @@ -9,6 +9,7 @@ import ( "sync" "time" + "github.com/lightningnetwork/lnd/keychain" "github.com/lightningnetwork/lnd/lnwallet" "github.com/roasbeef/btcd/btcec" "github.com/roasbeef/btcd/chaincfg" @@ -27,9 +28,25 @@ const ( ) var ( - lnNamespace = []byte("ln") - rootKey = []byte("ln-root") + // waddrmgrNamespaceKey is the namespace key that the waddrmgr state is + // stored within the top-level waleltdb buckets of btcwallet. waddrmgrNamespaceKey = []byte("waddrmgr") + + // lightningKeyScope is the key scope that will be used within the + // waddrmgr to create an HD chain for deriving all of our required + // keys. We'll ensure this this scope is created upon start. + lightningKeyScope = waddrmgr.KeyScope{ + Purpose: keychain.BIP0043Purpose, + Coin: 0, + } + + // lightningAddrSchema is the scope addr schema for all keys that we + // derive. We'll treat them all as p2wkh addresses, as atm we must + // specify a particular type. + lightningAddrSchema = waddrmgr.ScopeAddrSchema{ + ExternalAddrType: waddrmgr.WitnessPubKey, + InternalAddrType: waddrmgr.WitnessPubKey, + } ) // BtcWallet is an implementation of the lnwallet.WalletController interface @@ -83,49 +100,23 @@ func New(cfg Config) (*BtcWallet, error) { wallet, err = loader.CreateNewWallet( pubPass, cfg.PrivatePass, cfg.HdSeed, ) - - switch { - // If the wallet already exists, then we'll ignore this error - // and proceed directly to opening the wallet. - case err == base.ErrExists: - - // Otherwise, there's a greater error here, and we'll return - // early. - case err != nil: + if err != nil { return nil, err } - - if err := loader.UnloadWallet(); err != nil { + } else { + // Wallet has been created and been initialized at this point, + // open it along with all the required DB namespaces, and the + // DB itself. + wallet, err = loader.OpenExistingWallet(pubPass, false) + if err != nil { return nil, err } } - // Wallet has been created and been initialized at this point, open it - // along with all the required DB namepsaces, and the DB itself. - wallet, err = loader.OpenExistingWallet(pubPass, false) - if err != nil { - return nil, err - } - - // Create a bucket within the wallet's database dedicated to storing - // our LN specific data. - db := wallet.Database() - err = walletdb.Update(db, func(tx walletdb.ReadWriteTx) error { - _, err := tx.CreateTopLevelBucket(lnNamespace) - if err != nil && err != walletdb.ErrBucketExists { - return err - } - - return nil - }) - if err != nil { - return nil, err - } - return &BtcWallet{ cfg: &cfg, wallet: wallet, - db: db, + db: wallet.Database(), chain: cfg.ChainSource, netParams: cfg.NetParams, utxoCache: make(map[wire.OutPoint]*wire.TxOut), @@ -143,6 +134,12 @@ func (b *BtcWallet) BackEnd() string { return "" } +// InternalWallet returns a pointer to the internal base wallet which is the +// core of btcwallet. +func (b *BtcWallet) InternalWallet() *base.Wallet { + return b.wallet +} + // Start initializes the underlying rpc connection, the wallet itself, and // begins syncing to the current available blockchain state. // @@ -165,6 +162,27 @@ func (b *BtcWallet) Start() error { return err } + // We'll now ensure that the KeyScope: (1017, 1) exists within the + // internal waddrmgr. We'll need this in order to properly generate the + // keys required for signing various contracts. + _, err := b.wallet.Manager.FetchScopedKeyManager(lightningKeyScope) + if err != nil { + // If the scope hasn't yet been created (it wouldn't been + // loaded by default if it was), then we'll manually create the + // scope for the first time ourselves. + err := walletdb.Update(b.db, func(tx walletdb.ReadWriteTx) error { + addrmgrNs := tx.ReadWriteBucket(waddrmgrNamespaceKey) + + _, err := b.wallet.Manager.NewScopedKeyManager( + addrmgrNs, lightningKeyScope, lightningAddrSchema, + ) + return err + }) + if err != nil { + return err + } + } + return nil } @@ -209,6 +227,8 @@ func (b *BtcWallet) ConfirmedBalance(confs int32, witness bool) (btcutil.Amount, balance = outputSum } + // TODO(roasbeef): remove witness only distinction? + return balance, nil } @@ -219,24 +239,22 @@ func (b *BtcWallet) ConfirmedBalance(confs int32, witness bool) (btcutil.Amount, // // This is a part of the WalletController interface. func (b *BtcWallet) NewAddress(t lnwallet.AddressType, change bool) (btcutil.Address, error) { - var addrType waddrmgr.AddressType + var keyScope waddrmgr.KeyScope switch t { case lnwallet.WitnessPubKey: - addrType = waddrmgr.WitnessPubKey + keyScope = waddrmgr.KeyScopeBIP0084 case lnwallet.NestedWitnessPubKey: - addrType = waddrmgr.NestedWitnessPubKey - case lnwallet.PubKeyHash: - addrType = waddrmgr.PubKeyHash + keyScope = waddrmgr.KeyScopeBIP0049Plus default: return nil, fmt.Errorf("unknown address type") } if change { - return b.wallet.NewChangeAddress(defaultAccount, addrType) + return b.wallet.NewChangeAddress(defaultAccount, keyScope) } - return b.wallet.NewAddress(defaultAccount, addrType) + return b.wallet.NewAddress(defaultAccount, keyScope) } // GetPrivKey retrieves the underlying private key associated with the passed