From 07c60c85f9a0f40685d20d297d5318e073593015 Mon Sep 17 00:00:00 2001 From: yyforyongyu Date: Tue, 10 Dec 2024 22:44:42 +0800 Subject: [PATCH] lnwallet: remove direct walletdb reference To make sure the db layer is not exposed and is only managed by the `btcwallet` package. --- lnwallet/btcwallet/btcwallet.go | 151 +++++--------------------------- lnwallet/btcwallet/signer.go | 89 +------------------ 2 files changed, 23 insertions(+), 217 deletions(-) diff --git a/lnwallet/btcwallet/btcwallet.go b/lnwallet/btcwallet/btcwallet.go index b9a909fbd..455d79ee0 100644 --- a/lnwallet/btcwallet/btcwallet.go +++ b/lnwallet/btcwallet/btcwallet.go @@ -57,14 +57,6 @@ const ( ) var ( - // waddrmgrNamespaceKey is the namespace key that the waddrmgr state is - // stored within the top-level walletdb buckets of btcwallet. - waddrmgrNamespaceKey = []byte("waddrmgr") - - // wtxmgrNamespaceKey is the namespace key that the wtxmgr state is - // stored within the top-level waleltdb buckets of btcwallet. - wtxmgrNamespaceKey = []byte("wtxmgr") - // 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. @@ -350,18 +342,7 @@ func (b *BtcWallet) Start() error { // it was added recently and older wallets don't know it // yet. Let's add it now. addrSchema := waddrmgr.ScopeAddrMap[scope] - err := walletdb.Update( - b.db, func(tx walletdb.ReadWriteTx) error { - addrmgrNs := tx.ReadWriteBucket( - waddrmgrNamespaceKey, - ) - - _, err := b.wallet.Manager.NewScopedKeyManager( - addrmgrNs, scope, addrSchema, - ) - return err - }, - ) + _, err := b.wallet.AddScopeManager(scope, addrSchema) if err != nil { return err } @@ -373,65 +354,27 @@ func (b *BtcWallet) Start() error { // 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) - - scope, err = b.wallet.Manager.NewScopedKeyManager( - addrmgrNs, b.chainKeyScope, lightningAddrSchema, - ) - return err - }) + manager, err := b.wallet.AddScopeManager( + b.chainKeyScope, lightningAddrSchema, + ) if err != nil { return err } + + scope = manager } + // If the wallet is not watch-only atm, and the user wants to migrate it + // to watch-only, we will set `convertToWatchOnly` to true so the wallet + // accounts are created and converted. + convertToWatchOnly := !walletIsWatchOnly && b.cfg.WatchOnly && + b.cfg.MigrateWatchOnly + // Now that the wallet is unlocked, we'll go ahead and make sure we // create accounts for all the key families we're going to use. This // will make it possible to list all the account/family xpubs in the // wallet list RPC. - err = walletdb.Update(b.db, func(tx walletdb.ReadWriteTx) error { - addrmgrNs := tx.ReadWriteBucket(waddrmgrNamespaceKey) - - // Generate all accounts that we could ever need. This includes - // all lnd key families as well as some key families used in - // external liquidity tools. - for keyFam := uint32(1); keyFam <= 255; keyFam++ { - // Otherwise, we'll check if the account already exists, - // if so, we can once again bail early. - _, err := scope.AccountName(addrmgrNs, keyFam) - if err == nil { - continue - } - - // If we reach this point, then the account hasn't yet - // been created, so we'll need to create it before we - // can proceed. - err = scope.NewRawAccount(addrmgrNs, keyFam) - if err != nil { - return err - } - } - - // If this is the first startup with remote signing and wallet - // migration turned on and the wallet wasn't previously - // migrated, we can do that now that we made sure all accounts - // that we need were derived correctly. - if !walletIsWatchOnly && b.cfg.WatchOnly && - b.cfg.MigrateWatchOnly { - - log.Infof("Migrating wallet to watch-only mode, " + - "purging all private key material") - - ns := tx.ReadWriteBucket(waddrmgrNamespaceKey) - err = b.wallet.Manager.ConvertToWatchingOnly(ns) - if err != nil { - return err - } - } - - return nil - }) + err = b.wallet.InitAccounts(scope, convertToWatchOnly, 255) if err != nil { return err } @@ -769,29 +712,8 @@ func (b *BtcWallet) ListAddresses(name string, for _, accntDetails := range accounts { accntScope := accntDetails.KeyScope - scopedMgr, err := b.wallet.Manager.FetchScopedKeyManager( - accntScope, - ) - if err != nil { - return nil, err - } - - var managedAddrs []waddrmgr.ManagedAddress - err = walletdb.View( - b.wallet.Database(), func(tx walletdb.ReadTx) error { - managedAddrs = nil - addrmgrNs := tx.ReadBucket(waddrmgrNamespaceKey) - return scopedMgr.ForEachAccountAddress( - addrmgrNs, accntDetails.AccountNumber, - func(a waddrmgr.ManagedAddress) error { - managedAddrs = append( - managedAddrs, a, - ) - - return nil - }, - ) - }, + managedAddrs, err := b.wallet.AccountManagedAddresses( + accntDetails.KeyScope, accntDetails.AccountNumber, ) if err != nil { return nil, err @@ -1817,18 +1739,8 @@ func (b *BtcWallet) GetRecoveryInfo() (bool, float64, error) { return isRecoveryMode, progress, nil } - // Query the wallet's birthday block height from db. - var birthdayBlock waddrmgr.BlockStamp - err := walletdb.View(b.db, func(tx walletdb.ReadTx) error { - var err error - addrmgrNs := tx.ReadBucket(waddrmgrNamespaceKey) - birthdayBlock, _, err = b.wallet.Manager.BirthdayBlock(addrmgrNs) - if err != nil { - return err - } - return nil - }) - + // Query the wallet's birthday block from db. + birthdayBlock, err := b.wallet.BirthdayBlock() if err != nil { // The wallet won't start until the backend is synced, thus the birthday // block won't be set and this particular error will be returned. We'll @@ -1886,27 +1798,12 @@ func (b *BtcWallet) GetRecoveryInfo() (bool, float64, error) { // by the passed transaction hash. If the transaction can't be found, then a // nil pointer is returned. func (b *BtcWallet) FetchTx(txHash chainhash.Hash) (*wire.MsgTx, error) { - var targetTx *wtxmgr.TxDetails - err := walletdb.View(b.db, func(tx walletdb.ReadTx) error { - wtxmgrNs := tx.ReadBucket(wtxmgrNamespaceKey) - txDetails, err := b.wallet.TxStore.TxDetails(wtxmgrNs, &txHash) - if err != nil { - return err - } - - targetTx = txDetails - - return nil - }) + tx, err := b.wallet.GetTransaction(txHash) if err != nil { return nil, err } - if targetTx == nil { - return nil, nil - } - - return &targetTx.TxRecord.MsgTx, nil + return tx.Summary.Tx, nil } // RemoveDescendants attempts to remove any transaction from the wallet's tx @@ -1914,15 +1811,7 @@ func (b *BtcWallet) FetchTx(txHash chainhash.Hash) (*wire.MsgTx, error) { // transaction. This remove propagates recursively down the chain of descendent // transactions. func (b *BtcWallet) RemoveDescendants(tx *wire.MsgTx) error { - txRecord, err := wtxmgr.NewTxRecordFromMsgTx(tx, time.Now()) - if err != nil { - return err - } - - return walletdb.Update(b.db, func(tx walletdb.ReadWriteTx) error { - wtxmgrNs := tx.ReadWriteBucket(wtxmgrNamespaceKey) - return b.wallet.TxStore.RemoveUnminedTx(wtxmgrNs, txRecord) - }) + return b.wallet.RemoveDescendants(tx) } // CheckMempoolAcceptance is a wrapper around `TestMempoolAccept` which checks diff --git a/lnwallet/btcwallet/signer.go b/lnwallet/btcwallet/signer.go index 97832a789..69f7ab609 100644 --- a/lnwallet/btcwallet/signer.go +++ b/lnwallet/btcwallet/signer.go @@ -13,7 +13,6 @@ import ( "github.com/btcsuite/btcd/txscript" "github.com/btcsuite/btcd/wire" "github.com/btcsuite/btcwallet/waddrmgr" - "github.com/btcsuite/btcwallet/walletdb" "github.com/lightningnetwork/lnd/input" "github.com/lightningnetwork/lnd/keychain" "github.com/lightningnetwork/lnd/lnwallet" @@ -71,26 +70,6 @@ func (b *BtcWallet) ScriptForOutput(output *wire.TxOut) ( return b.wallet.ScriptForOutput(output) } -// deriveFromKeyLoc attempts to derive a private key using a fully specified -// KeyLocator. -func deriveFromKeyLoc(scopedMgr *waddrmgr.ScopedKeyManager, - addrmgrNs walletdb.ReadWriteBucket, - keyLoc keychain.KeyLocator) (*btcec.PrivateKey, error) { - - path := waddrmgr.DerivationPath{ - InternalAccount: uint32(keyLoc.Family), - Account: uint32(keyLoc.Family), - Branch: 0, - Index: keyLoc.Index, - } - addr, err := scopedMgr.DeriveFromKeyPath(addrmgrNs, path) - if err != nil { - return nil, err - } - - return addr.(waddrmgr.ManagedPubKeyAddress).PrivKey() -} - // deriveKeyByBIP32Path derives a key described by a BIP32 path. We expect the // first three elements of the path to be hardened according to BIP44, so they // must be a number >= 2^31. @@ -169,36 +148,14 @@ func (b *BtcWallet) deriveKeyByBIP32Path(path []uint32) (*btcec.PrivateKey, Purpose: purpose, Coin: coinType, } - scopedMgr, err := b.wallet.Manager.FetchScopedKeyManager(scope) - if err != nil { - return nil, fmt.Errorf("error fetching manager for scope %v: "+ - "%w", scope, err) - } - - // Let's see if we can hit the private key cache. keyPath := waddrmgr.DerivationPath{ InternalAccount: account, Account: account, Branch: change, Index: index, } - privKey, err := scopedMgr.DeriveFromKeyPathCache(keyPath) - if err == nil { - return privKey, nil - } - // The key wasn't in the cache, let's fully derive it now. - err = walletdb.View(b.db, func(tx walletdb.ReadTx) error { - addrmgrNs := tx.ReadBucket(waddrmgrNamespaceKey) - - addr, err := scopedMgr.DeriveFromKeyPath(addrmgrNs, keyPath) - if err != nil { - return fmt.Errorf("error deriving private key: %w", err) - } - - privKey, err = addr.(waddrmgr.ManagedPubKeyAddress).PrivKey() - return err - }) + privKey, err := b.wallet.DeriveFromKeyPath(scope, keyPath) if err != nil { return nil, fmt.Errorf("error deriving key from path %#v: %w", keyPath, err) @@ -225,55 +182,15 @@ func (b *BtcWallet) deriveKeyByLocator( keyLoc keychain.KeyLocator) (*btcec.PrivateKey, error) { // We'll assume the special lightning key scope in this case. - scopedMgr, err := b.wallet.Manager.FetchScopedKeyManager( - b.chainKeyScope, - ) - if err != nil { - return nil, err - } - - // First try to read the key from the cached store, if this fails, then - // we'll fall through to the method below that requires a database - // transaction. + scope := b.chainKeyScope path := waddrmgr.DerivationPath{ InternalAccount: uint32(keyLoc.Family), Account: uint32(keyLoc.Family), Branch: 0, Index: keyLoc.Index, } - privKey, err := scopedMgr.DeriveFromKeyPathCache(path) - if err == nil { - return privKey, nil - } - var key *btcec.PrivateKey - err = walletdb.Update(b.db, func(tx walletdb.ReadWriteTx) error { - addrmgrNs := tx.ReadWriteBucket(waddrmgrNamespaceKey) - - key, err = deriveFromKeyLoc(scopedMgr, addrmgrNs, keyLoc) - if waddrmgr.IsError(err, waddrmgr.ErrAccountNotFound) { - // If we've reached this point, then the account - // doesn't yet exist, so we'll create it now to ensure - // we can sign. - acctErr := scopedMgr.NewRawAccount( - addrmgrNs, uint32(keyLoc.Family), - ) - if acctErr != nil { - return acctErr - } - - // Now that we know the account exists, we'll attempt - // to re-derive the private key. - key, err = deriveFromKeyLoc( - scopedMgr, addrmgrNs, keyLoc, - ) - if err != nil { - return err - } - } - - return err - }) + key, err := b.wallet.DeriveFromKeyPathAddAccount(scope, path) if err != nil { return nil, err }