diff --git a/docs/release-notes/release-notes-0.19.0.md b/docs/release-notes/release-notes-0.19.0.md index fed1a87ae..e4ce83116 100644 --- a/docs/release-notes/release-notes-0.19.0.md +++ b/docs/release-notes/release-notes-0.19.0.md @@ -91,6 +91,9 @@ * [Pass through](https://github.com/lightningnetwork/lnd/pull/9601) the unused `MaxPeers` configuration variable for neutrino mode. +* [Fixed](https://github.com/lightningnetwork/lnd/pull/9609) a bug that may + cause `listunspent` to give inaccurate wallet UTXOs. + # New Features * Add support for [archiving channel backup](https://github.com/lightningnetwork/lnd/pull/9232) diff --git a/go.mod b/go.mod index 1953a0a6c..98f35eef2 100644 --- a/go.mod +++ b/go.mod @@ -11,7 +11,7 @@ require ( github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0 github.com/btcsuite/btclog v0.0.0-20241003133417-09c4e92e319c github.com/btcsuite/btclog/v2 v2.0.1-0.20250110154127-3ae4bf1cb318 - github.com/btcsuite/btcwallet v0.16.10 + github.com/btcsuite/btcwallet v0.16.11 github.com/btcsuite/btcwallet/wallet/txauthor v1.3.5 github.com/btcsuite/btcwallet/wallet/txrules v1.2.2 github.com/btcsuite/btcwallet/walletdb v1.4.4 diff --git a/go.sum b/go.sum index d7b4a4553..9c69f3fc6 100644 --- a/go.sum +++ b/go.sum @@ -95,8 +95,8 @@ github.com/btcsuite/btclog v0.0.0-20241003133417-09c4e92e319c/go.mod h1:w7xnGOhw github.com/btcsuite/btclog/v2 v2.0.1-0.20250110154127-3ae4bf1cb318 h1:oCjIcinPt7XQ644MP/22JcjYEC84qRc3bRBH0d7Hhd4= github.com/btcsuite/btclog/v2 v2.0.1-0.20250110154127-3ae4bf1cb318/go.mod h1:XItGUfVOxotJL8kkuk2Hj3EVow5KCugXl3wWfQ6K0AE= github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg= -github.com/btcsuite/btcwallet v0.16.10 h1:SDMS0Gp7oEJVvyZNQ6gDYkpkvp/cSMRcAAy3fvO3vTk= -github.com/btcsuite/btcwallet v0.16.10/go.mod h1:1HJXYbjJzgumlnxOC2+ViR1U+gnHWoOn7WeK5OfY1eU= +github.com/btcsuite/btcwallet v0.16.11 h1:c8RgW/HO79if8P+KFQLQE00ITmFnLPKAzIy9FwxE37A= +github.com/btcsuite/btcwallet v0.16.11/go.mod h1:1HJXYbjJzgumlnxOC2+ViR1U+gnHWoOn7WeK5OfY1eU= github.com/btcsuite/btcwallet/wallet/txauthor v1.3.5 h1:Rr0njWI3r341nhSPesKQ2JF+ugDSzdPoeckS75SeDZk= github.com/btcsuite/btcwallet/wallet/txauthor v1.3.5/go.mod h1:+tXJ3Ym0nlQc/iHSwW1qzjmPs3ev+UVWMbGgfV1OZqU= github.com/btcsuite/btcwallet/wallet/txrules v1.2.2 h1:YEO+Lx1ZJJAtdRrjuhXjWrYsmAk26wLTlNzxt2q0lhk= diff --git a/itest/flakes.go b/itest/flakes.go index 68c36a738..8dd52b659 100644 --- a/itest/flakes.go +++ b/itest/flakes.go @@ -3,9 +3,7 @@ package itest import ( "time" - "github.com/btcsuite/btcd/btcutil" "github.com/lightningnetwork/lnd/lntest" - "github.com/lightningnetwork/lnd/lntest/node" ) // flakePreimageSettlement documents a flake found when testing the preimage @@ -34,19 +32,6 @@ func flakePreimageSettlement(ht *lntest.HarnessTest) { time.Sleep(2 * time.Second) } -// flakeFundExtraUTXO documents a flake found when testing the sweeping behavior -// of the given node, which would fail due to no wallet UTXO available, while -// there should be enough. -// -// TODO(yy): remove it once the issue is resolved. -func flakeFundExtraUTXO(ht *lntest.HarnessTest, node *node.HarnessNode) { - // The node should have enough wallet UTXOs here to sweep the HTLC in - // the end of this test. However, due to a known issue, the node's - // wallet may report there's no UTXO available. For details, - // - https://github.com/lightningnetwork/lnd/issues/8786 - ht.FundCoins(btcutil.SatoshiPerBitcoin, node) -} - // flakeTxNotifierNeutrino documents a flake found when running force close // tests using neutrino backend, which is a race between two notifications - one // for the spending notification, the other for the block which contains the @@ -127,3 +112,28 @@ func flakePaymentStreamReturnEarly() { // commitment. time.Sleep(2 * time.Second) } + +// flakeRaceInBitcoinClientNotifications documents a bug found that the +// `ListUnspent` gives inaccurate results. In specific, +// - an output is confirmed in block X, which is under the process of being +// credited to our wallet. +// - `ListUnspent` is called between the above process, returning an +// inaccurate result, causing the sweeper to think there's no wallet utxo. +// - the sweeping will fail at block X due to not enough inputs. +// +// Under the hood, the RPC client created for handling wallet txns and handling +// block notifications are independent. For the block notification, which is +// registered via `RegisterBlockEpochNtfn`, is managed by the `chainntnfs`, +// which is hooked to a bitcoind client created at startup. For the wallet, it +// uses another bitcoind client to receive online events. Although they share +// the same bitcoind RPC conn, these two clients are acting independently. +// With this setup, it means there's no coordination between the two system - +// `lnwallet` and `chainntnfs` can disagree on the latest onchain state for a +// short period, causing an inconsistent state which leads to the failed +// sweeping attempt. +// +// TODO(yy): We need to adhere to the SSOT principle, and make the effort to +// ensure the whole system only uses one bitcoind client. +func flakeRaceInBitcoinClientNotifications(ht *lntest.HarnessTest) { + ht.MineEmptyBlocks(1) +} diff --git a/itest/list_exclude_test.go b/itest/list_exclude_test.go index 0f398c208..fd0e1c03a 100644 --- a/itest/list_exclude_test.go +++ b/itest/list_exclude_test.go @@ -69,6 +69,13 @@ var excludedTestsWindows = []string{ "query blinded route", "data loss protection", + + // The following restart cases will fail in windows due to aggregation + // can sometimes miss grouping one or two inputs in the same sweeping + // tx, which is likely caused by how the blocks are notified in windows, + // more investigation is needed. + "channel force close-anchor restart", + "channel force close-simple taproot restart", } // filterWindowsFlakyTests filters out the flaky tests that are excluded from diff --git a/itest/lnd_multi-hop_force_close_test.go b/itest/lnd_multi-hop_force_close_test.go index 9907f6a59..84f8c8d44 100644 --- a/itest/lnd_multi-hop_force_close_test.go +++ b/itest/lnd_multi-hop_force_close_test.go @@ -341,8 +341,6 @@ func runLocalClaimOutgoingHTLC(ht *lntest.HarnessTest, ht.FundCoins(btcutil.SatoshiPerBitcoin, bob) } - flakeFundExtraUTXO(ht, bob) - // Now that our channels are set up, we'll send two HTLC's from Alice // to Carol. The first HTLC will be universally considered "dust", // while the second will be a proper fully valued HTLC. @@ -685,7 +683,6 @@ func runMultiHopReceiverPreimageClaim(ht *lntest.HarnessTest, // Fund Carol one UTXO so she can sweep outputs. ht.FundCoins(btcutil.SatoshiPerBitcoin, carol) - flakeFundExtraUTXO(ht, carol) // If this is a taproot channel, then we'll need to make some manual // route hints so Alice can actually find a route. @@ -1601,8 +1598,6 @@ func runLocalClaimIncomingHTLC(ht *lntest.HarnessTest, // Fund Carol one UTXO so she can sweep outputs. ht.FundCoins(btcutil.SatoshiPerBitcoin, carol) - flakeFundExtraUTXO(ht, carol) - flakeFundExtraUTXO(ht, bob) // If this is a taproot channel, then we'll need to make some manual // route hints so Alice can actually find a route. @@ -1897,7 +1892,6 @@ func runLocalClaimIncomingHTLCLeased(ht *lntest.HarnessTest, // Fund Carol one UTXO so she can sweep outputs. ht.FundCoins(btcutil.SatoshiPerBitcoin, carol) - flakeFundExtraUTXO(ht, carol) // With the network active, we'll now add a new hodl invoice at Carol's // end. Make sure the cltv expiry delta is large enough, otherwise Bob @@ -2230,7 +2224,6 @@ func runLocalPreimageClaim(ht *lntest.HarnessTest, // Fund Carol one UTXO so she can sweep outputs. ht.FundCoins(btcutil.SatoshiPerBitcoin, carol) - flakeFundExtraUTXO(ht, carol) // If this is a taproot channel, then we'll need to make some manual // route hints so Alice can actually find a route. @@ -2490,7 +2483,6 @@ func runLocalPreimageClaimLeased(ht *lntest.HarnessTest, // Fund Carol one UTXO so she can sweep outputs. ht.FundCoins(btcutil.SatoshiPerBitcoin, carol) - flakeFundExtraUTXO(ht, carol) // With the network active, we'll now add a new hodl invoice at Carol's // end. Make sure the cltv expiry delta is large enough, otherwise Bob @@ -2842,7 +2834,6 @@ func runHtlcAggregation(ht *lntest.HarnessTest, // We need one additional UTXO to create the sweeping tx for the // second-level success txes. ht.FundCoins(btcutil.SatoshiPerBitcoin, bob) - flakeFundExtraUTXO(ht, bob) // If this is a taproot channel, then we'll need to make some manual // route hints so Alice+Carol can actually find a route. diff --git a/itest/lnd_sweep_test.go b/itest/lnd_sweep_test.go index 8f94db7b7..63c489853 100644 --- a/itest/lnd_sweep_test.go +++ b/itest/lnd_sweep_test.go @@ -115,8 +115,6 @@ func testSweepCPFPAnchorOutgoingTimeout(ht *lntest.HarnessTest) { ht.FundCoins(btcutil.SatoshiPerBitcoin, bob) } - flakeFundExtraUTXO(ht, bob) - // Subscribe the invoice. streamCarol := carol.RPC.SubscribeSingleInvoice(payHash[:]) @@ -342,6 +340,8 @@ func testSweepCPFPAnchorOutgoingTimeout(ht *lntest.HarnessTest) { // needed to clean up the mempool. ht.MineBlocksAndAssertNumTxes(1, 2) + flakeRaceInBitcoinClientNotifications(ht) + // The above mined block should confirm Bob's force close tx, and his // contractcourt will offer the HTLC to his sweeper. We are not testing // the HTLC sweeping behaviors so we just perform a simple check and @@ -435,8 +435,6 @@ func testSweepCPFPAnchorIncomingTimeout(ht *lntest.HarnessTest) { ht.FundCoins(btcutil.SatoshiPerBitcoin, bob) } - flakeFundExtraUTXO(ht, bob) - // Subscribe the invoice. streamCarol := carol.RPC.SubscribeSingleInvoice(payHash[:]) 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/log.go b/lnwallet/btcwallet/log.go index d0a589fed..aca9fec4d 100644 --- a/lnwallet/btcwallet/log.go +++ b/lnwallet/btcwallet/log.go @@ -2,6 +2,9 @@ package btcwallet import ( "github.com/btcsuite/btclog/v2" + "github.com/btcsuite/btcwallet/chain" + btcwallet "github.com/btcsuite/btcwallet/wallet" + "github.com/btcsuite/btcwallet/wtxmgr" "github.com/lightningnetwork/lnd/build" ) @@ -29,4 +32,8 @@ func DisableLog() { // btclog. func UseLogger(logger btclog.Logger) { log = logger + + btcwallet.UseLogger(logger) + wtxmgr.UseLogger(logger) + chain.UseLogger(logger) } 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 } diff --git a/lnwallet/log.go b/lnwallet/log.go index 5fde019d7..6cac9f77f 100644 --- a/lnwallet/log.go +++ b/lnwallet/log.go @@ -2,9 +2,6 @@ package lnwallet import ( "github.com/btcsuite/btclog/v2" - "github.com/btcsuite/btcwallet/chain" - btcwallet "github.com/btcsuite/btcwallet/wallet" - "github.com/btcsuite/btcwallet/wtxmgr" "github.com/lightningnetwork/lnd/build" "github.com/lightningnetwork/lnd/lnwallet/chainfee" ) @@ -31,8 +28,5 @@ func DisableLog() { func UseLogger(logger btclog.Logger) { walletLog = logger - btcwallet.UseLogger(logger) - wtxmgr.UseLogger(logger) - chain.UseLogger(logger) chainfee.UseLogger(logger) } diff --git a/log.go b/log.go index 5d1f2567f..fbb56465a 100644 --- a/log.go +++ b/log.go @@ -54,6 +54,7 @@ import ( "github.com/lightningnetwork/lnd/routing/localchans" "github.com/lightningnetwork/lnd/rpcperms" "github.com/lightningnetwork/lnd/signal" + "github.com/lightningnetwork/lnd/sqldb" "github.com/lightningnetwork/lnd/sweep" "github.com/lightningnetwork/lnd/tor" "github.com/lightningnetwork/lnd/watchtower" @@ -204,6 +205,7 @@ func SetupLoggers(root *build.SubLoggerManager, interceptor signal.Interceptor) AddV1SubLogger(root, graphdb.Subsystem, interceptor, graphdb.UseLogger) AddSubLogger(root, chainio.Subsystem, interceptor, chainio.UseLogger) AddSubLogger(root, msgmux.Subsystem, interceptor, msgmux.UseLogger) + AddSubLogger(root, sqldb.Subsystem, interceptor, sqldb.UseLogger) } // AddSubLogger is a helper method to conveniently create and register the diff --git a/sqldb/interfaces.go b/sqldb/interfaces.go index 3197d7f09..6f3278c78 100644 --- a/sqldb/interfaces.go +++ b/sqldb/interfaces.go @@ -247,6 +247,9 @@ func ExecuteSQLTransactionWithRetry(ctx context.Context, makeTx MakeTx, tx, err := makeTx() if err != nil { dbErr := MapSQLError(err) + log.Tracef("Failed to makeTx: err=%v, dbErr=%v", err, + dbErr) + if IsSerializationError(dbErr) { // Nothing to roll back here, since we haven't // even get a transaction yet. We'll just wait @@ -266,6 +269,8 @@ func ExecuteSQLTransactionWithRetry(ctx context.Context, makeTx MakeTx, }() if bodyErr := txBody(tx); bodyErr != nil { + log.Tracef("Error in txBody: %v", bodyErr) + // Roll back the transaction, then attempt a random // backoff and try again if the error was a // serialization error. @@ -285,6 +290,8 @@ func ExecuteSQLTransactionWithRetry(ctx context.Context, makeTx MakeTx, // Commit transaction. if commitErr := tx.Commit(); commitErr != nil { + log.Tracef("Failed to commit tx: %v", commitErr) + // Roll back the transaction, then attempt a random // backoff and try again if the error was a // serialization error. diff --git a/sweep/fee_bumper.go b/sweep/fee_bumper.go index 6a796e22d..b081fe479 100644 --- a/sweep/fee_bumper.go +++ b/sweep/fee_bumper.go @@ -1371,7 +1371,7 @@ func (t *TxPublisher) createAndPublishTx( return fn.Some(*result) } - log.Infof("Replaced tx=%v with new tx=%v", oldTx.TxHash(), + log.Debugf("Replaced tx=%v with new tx=%v", oldTx.TxHash(), sweepCtx.tx.TxHash()) // Otherwise, it's a successful RBF, set the event and return. diff --git a/sweep/sweeper.go b/sweep/sweeper.go index 9684039e4..69cf9c5d8 100644 --- a/sweep/sweeper.go +++ b/sweep/sweeper.go @@ -824,6 +824,9 @@ func (s *UtxoSweeper) sweep(set InputSet) error { return fmt.Errorf("gen sweep script: %w", err) } s.currentOutputScript = fn.Some(addr) + + log.Debugf("Created sweep DeliveryAddress %x", + addr.DeliveryAddress) } sweepAddr, err := s.currentOutputScript.UnwrapOrErr( @@ -1725,8 +1728,8 @@ func (s *UtxoSweeper) handleBumpEventTxReplaced(resp *bumpResp) error { s.cfg.Wallet.CancelRebroadcast(oldTxid) log.Infof("RBFed tx=%v(fee=%v sats, feerate=%v sats/kw) with new "+ - "tx=%v(fee=%v, "+"feerate=%v)", record.Txid, record.Fee, - record.FeeRate, tr.Txid, tr.Fee, tr.FeeRate) + "tx=%v(fee=%v sats, feerate=%v sats/kw)", record.Txid, + record.Fee, record.FeeRate, tr.Txid, tr.Fee, tr.FeeRate) // The old sweeping tx has been replaced by a new one, we will update // the tx record in the sweeper db.