Skip to content

Commit

Permalink
x - lnwallet: remove direct db reference
Browse files Browse the repository at this point in the history
  • Loading branch information
yyforyongyu committed Dec 10, 2024
1 parent 48c8da1 commit 0967610
Show file tree
Hide file tree
Showing 2 changed files with 20 additions and 217 deletions.
148 changes: 17 additions & 131 deletions lnwallet/btcwallet/btcwallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -344,18 +336,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
}
Expand All @@ -367,65 +348,24 @@ 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
}

watchOnly := !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, watchOnly)
if err != nil {
return err
}
Expand Down Expand Up @@ -762,29 +702,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.AccountNumber,
)
if err != nil {
return nil, err
Expand Down Expand Up @@ -1812,18 +1731,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
Expand Down Expand Up @@ -1881,43 +1790,20 @@ 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
// store (that may be unconfirmed) that spends outputs created by the passed
// 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
Expand Down
89 changes: 3 additions & 86 deletions lnwallet/btcwallet/signer.go
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -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.
Expand Down Expand Up @@ -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)
Expand All @@ -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
}
Expand Down

0 comments on commit 0967610

Please sign in to comment.