Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve the performace of LeaseOutput #8961

Merged
merged 9 commits into from
Aug 21, 2024
5 changes: 5 additions & 0 deletions docs/release-notes/release-notes-0.18.3.md
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,11 @@ commitment when the channel was force closed.
* [Allow](https://github.com/lightningnetwork/lnd/pull/8845) multiple etcd hosts
to be specified in db.etcd.host.

* Improved the internal [`LeaseOutput`
method](https://github.com/lightningnetwork/lnd/pull/8961) to be more
efficient, which improves the performance of related RPC calls such as
`LeaseOutput`, `SendCoins`, and PSBT funding process.

## RPC Updates

* [`xImportMissionControl`](https://github.com/lightningnetwork/lnd/pull/8779)
Expand Down
2 changes: 1 addition & 1 deletion go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ require (
github.com/btcsuite/btcd/btcutil/psbt v1.1.8
github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f
github.com/btcsuite/btcwallet v0.16.10-0.20240718224643-db3a4a2543bd
github.com/btcsuite/btcwallet v0.16.10-0.20240809133323-7d3434c65ae2
github.com/btcsuite/btcwallet/wallet/txauthor v1.3.4
github.com/btcsuite/btcwallet/wallet/txrules v1.2.1
github.com/btcsuite/btcwallet/walletdb v1.4.2
Expand Down
4 changes: 2 additions & 2 deletions go.sum
Original file line number Diff line number Diff line change
Expand Up @@ -92,8 +92,8 @@ github.com/btcsuite/btcd/chaincfg/chainhash v1.1.0/go.mod h1:7SFka0XMvUgj3hfZtyd
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f h1:bAs4lUbRJpnnkd9VhRV3jjAVU7DJVjMaK+IsvSeZvFo=
github.com/btcsuite/btclog v0.0.0-20170628155309-84c8d2346e9f/go.mod h1:TdznJufoqS23FtqVCzL0ZqgP5MqXbb4fg/WgDys70nA=
github.com/btcsuite/btcutil v0.0.0-20190425235716-9e5f4b9a998d/go.mod h1:+5NJ2+qvTyV9exUAL/rxXi3DcLg2Ts+ymUAY5y4NvMg=
github.com/btcsuite/btcwallet v0.16.10-0.20240718224643-db3a4a2543bd h1:QDb8foTCRoXrfoZVEzSYgSde16MJh4gCtCin8OCS0kI=
github.com/btcsuite/btcwallet v0.16.10-0.20240718224643-db3a4a2543bd/go.mod h1:X2xDre+j1QphTRo54y2TikUzeSvreL1t1aMXrD8Kc5A=
github.com/btcsuite/btcwallet v0.16.10-0.20240809133323-7d3434c65ae2 h1:qa4Avm7p97JroZZyMJADbEb9u853pjleJYSeitENvLc=
github.com/btcsuite/btcwallet v0.16.10-0.20240809133323-7d3434c65ae2/go.mod h1:X2xDre+j1QphTRo54y2TikUzeSvreL1t1aMXrD8Kc5A=
github.com/btcsuite/btcwallet/wallet/txauthor v1.3.4 h1:poyHFf7+5+RdxNp5r2T6IBRD7RyraUsYARYbp/7t4D8=
github.com/btcsuite/btcwallet/wallet/txauthor v1.3.4/go.mod h1:GETGDQuyq+VFfH1S/+/7slLM/9aNa4l7P4ejX6dJfb0=
github.com/btcsuite/btcwallet/wallet/txrules v1.2.1 h1:UZo7YRzdHbwhK7Rhv3PO9bXgTxiOH45edK5qdsdiatk=
Expand Down
8 changes: 0 additions & 8 deletions itest/lnd_hold_invoice_force_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -95,10 +95,6 @@ func testHoldInvoiceForceClose(ht *lntest.HarnessTest) {
// We first mine enough blocks to trigger an invoice cancelation.
ht.MineBlocks(int(blocksTillCancel))

// Wait for the nodes to be synced.
ht.WaitForBlockchainSync(alice)
ht.WaitForBlockchainSync(bob)

// Check that the invoice is canceled by Bob.
err := wait.NoError(func() error {
inv := bob.RPC.LookupInvoice(payHash[:])
Expand Down Expand Up @@ -135,10 +131,6 @@ func testHoldInvoiceForceClose(ht *lntest.HarnessTest) {
// invoice cancelation message was received by Alice.
ht.MineBlocks(int(blocksTillForce - blocksTillCancel))

// Wait for the nodes to be synced.
ht.WaitForBlockchainSync(alice)
ht.WaitForBlockchainSync(bob)

// Check that Alice has not closed the channel because there are no
// outgoing HTLCs in her channel as the only HTLC has already been
// canceled.
Expand Down
1 change: 0 additions & 1 deletion itest/lnd_psbt_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1578,7 +1578,6 @@ func sendAllCoinsToAddrType(ht *lntest.HarnessTest,
})

ht.MineBlocksAndAssertNumTxes(1, 1)
ht.WaitForBlockchainSync(hn)
}

// testPsbtChanFundingFailFlow tests the failing of a funding flow by the
Expand Down
4 changes: 0 additions & 4 deletions itest/lnd_route_blinding_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -852,10 +852,6 @@ func testErrorHandlingOnChainFailure(ht *lntest.HarnessTest) {
ht.AssertNumPendingSweeps(ht.Bob, 0)
ht.MineBlocksAndAssertNumTxes(1, 1)

// Assert that the HTLC has cleared.
ht.WaitForBlockchainSync(ht.Bob)
ht.WaitForBlockchainSync(ht.Alice)

ht.AssertHTLCNotActive(ht.Bob, testCase.channels[0], hash[:])
ht.AssertHTLCNotActive(ht.Alice, testCase.channels[0], hash[:])

Expand Down
12 changes: 9 additions & 3 deletions lnrpc/walletrpc/psbt.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,7 +56,13 @@ func lockInputs(w lnwallet.WalletController,
},
}

expiration, pkScript, value, err := w.LeaseOutput(
// Get the details about this outpoint.
utxo, err := w.FetchOutpointInfo(&lock.Outpoint)
guggero marked this conversation as resolved.
Show resolved Hide resolved
if err != nil {
return nil, fmt.Errorf("fetch outpoint info: %w", err)
}

expiration, err := w.LeaseOutput(
lock.LockID, lock.Outpoint,
chanfunding.DefaultLockDuration,
)
Expand All @@ -80,8 +86,8 @@ func lockInputs(w lnwallet.WalletController,
}

lock.Expiration = expiration
lock.PkScript = pkScript
lock.Value = int64(value)
lock.PkScript = utxo.PkScript
lock.Value = int64(utxo.Value)
locks[idx] = lock
}

Expand Down
4 changes: 2 additions & 2 deletions lnrpc/walletrpc/walletkit_server.go
Original file line number Diff line number Diff line change
Expand Up @@ -490,7 +490,7 @@ func (w *WalletKit) LeaseOutput(ctx context.Context,
// other concurrent processes attempting to lease the same UTXO.
var expiration time.Time
err = w.cfg.CoinSelectionLocker.WithCoinSelectLock(func() error {
expiration, _, _, err = w.cfg.Wallet.LeaseOutput(
expiration, err = w.cfg.Wallet.LeaseOutput(
lockID, *op, duration,
)
return err
Expand Down Expand Up @@ -1142,7 +1142,7 @@ func (w *WalletKit) sweepNewInput(op *wire.OutPoint, currentHeight uint32,
//
// We'll gather all of the information required by the UtxoSweeper in
// order to sweep the output.
utxo, err := w.cfg.Wallet.FetchInputInfo(op)
utxo, err := w.cfg.Wallet.FetchOutpointInfo(op)
if err != nil {
return err
}
Expand Down
16 changes: 12 additions & 4 deletions lntest/mock/walletcontroller.go
Original file line number Diff line number Diff line change
Expand Up @@ -43,9 +43,9 @@ func (w *WalletController) BackEnd() string {
return "mock"
}

// FetchInputInfo will be called to get info about the inputs to the funding
// FetchOutpointInfo will be called to get info about the inputs to the funding
// transaction.
func (w *WalletController) FetchInputInfo(
func (w *WalletController) FetchOutpointInfo(
prevOut *wire.OutPoint) (*lnwallet.Utxo, error) {

utxo := &lnwallet.Utxo{
Expand Down Expand Up @@ -195,9 +195,9 @@ func (w *WalletController) ListTransactionDetails(int32, int32,

// LeaseOutput returns the current time and a nil error.
func (w *WalletController) LeaseOutput(wtxmgr.LockID, wire.OutPoint,
time.Duration) (time.Time, []byte, btcutil.Amount, error) {
time.Duration) (time.Time, error) {

return time.Now(), nil, 0, nil
return time.Now(), nil
}

// ReleaseOutput currently does nothing.
Expand Down Expand Up @@ -292,3 +292,11 @@ func (w *WalletController) RemoveDescendants(*wire.MsgTx) error {
func (w *WalletController) CheckMempoolAcceptance(tx *wire.MsgTx) error {
return nil
}

// FetchDerivationInfo queries for the wallet's knowledge of the passed
// pkScript and constructs the derivation info and returns it.
func (w *WalletController) FetchDerivationInfo(
pkScript []byte) (*psbt.Bip32Derivation, error) {

return nil, nil
}
24 changes: 4 additions & 20 deletions lnwallet/btcwallet/btcwallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -1079,36 +1079,20 @@ func (b *BtcWallet) CreateSimpleTx(inputs fn.Set[wire.OutPoint],
//
// NOTE: This method requires the global coin selection lock to be held.
func (b *BtcWallet) LeaseOutput(id wtxmgr.LockID, op wire.OutPoint,
duration time.Duration) (time.Time, []byte, btcutil.Amount, error) {
duration time.Duration) (time.Time, error) {

// Make sure we don't attempt to double lock an output that's been
// locked by the in-memory implementation.
if b.wallet.LockedOutpoint(op) {
return time.Time{}, nil, 0, wtxmgr.ErrOutputAlreadyLocked
return time.Time{}, wtxmgr.ErrOutputAlreadyLocked
}

lockedUntil, err := b.wallet.LeaseOutput(id, op, duration)
if err != nil {
return time.Time{}, nil, 0, err
return time.Time{}, err
}

// Get the pkScript and value for this lock from the list of all leased
// outputs.
allLeases, err := b.wallet.ListLeasedOutputs()
if err != nil {
return time.Time{}, nil, 0, err
}

for _, lease := range allLeases {
if lease.Outpoint == op {
return lockedUntil, lease.PkScript,
btcutil.Amount(lease.Value), nil
}
}

// We MUST find the leased output in the loop above, otherwise something
// is seriously wrong.
return time.Time{}, nil, 0, wtxmgr.ErrUnknownOutput
return lockedUntil, nil
}

// ListLeasedOutputs returns a list of all currently locked outputs.
Expand Down
18 changes: 12 additions & 6 deletions lnwallet/btcwallet/signer.go
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import (
"github.com/btcsuite/btcd/btcec/v2/schnorr"
"github.com/btcsuite/btcd/btcutil"
"github.com/btcsuite/btcd/btcutil/hdkeychain"
"github.com/btcsuite/btcd/btcutil/psbt"
"github.com/btcsuite/btcd/chaincfg/chainhash"
"github.com/btcsuite/btcd/txscript"
"github.com/btcsuite/btcd/wire"
Expand All @@ -18,18 +19,16 @@ import (
"github.com/lightningnetwork/lnd/lnwallet"
)

// FetchInputInfo queries for the WalletController's knowledge of the passed
// FetchOutpointInfo queries for the WalletController's knowledge of the passed
// outpoint. If the base wallet determines this output is under its control,
// then the original txout should be returned. Otherwise, a non-nil error value
// of ErrNotMine should be returned instead.
//
// This is a part of the WalletController interface.
func (b *BtcWallet) FetchInputInfo(prevOut *wire.OutPoint) (*lnwallet.Utxo,
func (b *BtcWallet) FetchOutpointInfo(prevOut *wire.OutPoint) (*lnwallet.Utxo,
error) {

prevTx, txOut, bip32, confirmations, err := b.wallet.FetchInputInfo(
prevOut,
)
prevTx, txOut, confirmations, err := b.wallet.FetchOutpointInfo(prevOut)
if err != nil {
return nil, err
}
Expand All @@ -51,11 +50,18 @@ func (b *BtcWallet) FetchInputInfo(prevOut *wire.OutPoint) (*lnwallet.Utxo,
PkScript: txOut.PkScript,
Confirmations: confirmations,
OutPoint: *prevOut,
Derivation: bip32,
PrevTx: prevTx,
}, nil
}

// FetchDerivationInfo queries for the wallet's knowledge of the passed
// pkScript and constructs the derivation info and returns it.
func (b *BtcWallet) FetchDerivationInfo(
pkScript []byte) (*psbt.Bip32Derivation, error) {

return b.wallet.FetchDerivationInfo(pkScript)
}

// ScriptForOutput returns the address, witness program and redeem script for a
// given UTXO. An error is returned if the UTXO does not belong to our wallet or
// it is not a managed pubKey address.
Expand Down
2 changes: 1 addition & 1 deletion lnwallet/chanfunding/assembler.go
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ type OutputLeaser interface {
// LeaseOutput leases a target output, rendering it unusable for coin
// selection.
LeaseOutput(i wtxmgr.LockID, o wire.OutPoint, d time.Duration) (
time.Time, []byte, btcutil.Amount, error)
time.Time, error)

// ReleaseOutput releases a target output, allowing it to be used for
// coin selection once again.
Expand Down
2 changes: 1 addition & 1 deletion lnwallet/chanfunding/wallet_assembler.go
Original file line number Diff line number Diff line change
Expand Up @@ -525,7 +525,7 @@ func (w *WalletAssembler) ProvisionChannel(r *Request) (Intent, error) {
for _, coin := range selectedCoins {
outpoint := coin.OutPoint

_, _, _, err = w.cfg.CoinLeaser.LeaseOutput(
_, err = w.cfg.CoinLeaser.LeaseOutput(
LndInternalLockID, outpoint,
DefaultReservationTimeout,
)
Expand Down
21 changes: 12 additions & 9 deletions lnwallet/interface.go
Original file line number Diff line number Diff line change
Expand Up @@ -126,8 +126,7 @@ type Utxo struct {
Confirmations int64
PkScript []byte
wire.OutPoint
Derivation *psbt.Bip32Derivation
PrevTx *wire.MsgTx
PrevTx *wire.MsgTx
}

// OutputDetail contains additional information on a destination address.
Expand Down Expand Up @@ -227,11 +226,16 @@ type TransactionSubscription interface {
// behavior of all interface methods in order to ensure identical behavior
// across all concrete implementations.
type WalletController interface {
// FetchInputInfo queries for the WalletController's knowledge of the
// passed outpoint. If the base wallet determines this output is under
// its control, then the original txout should be returned. Otherwise,
// a non-nil error value of ErrNotMine should be returned instead.
FetchInputInfo(prevOut *wire.OutPoint) (*Utxo, error)
// FetchOutpointInfo queries for the WalletController's knowledge of
// the passed outpoint. If the base wallet determines this output is
// under its control, then the original txout should be returned.
// Otherwise, a non-nil error value of ErrNotMine should be returned
// instead.
FetchOutpointInfo(prevOut *wire.OutPoint) (*Utxo, error)

// FetchDerivationInfo queries for the wallet's knowledge of the passed
// pkScript and constructs the derivation info and returns it.
FetchDerivationInfo(pkScript []byte) (*psbt.Bip32Derivation, error)

// ScriptForOutput returns the address, witness program and redeem
// script for a given UTXO. An error is returned if the UTXO does not
Expand Down Expand Up @@ -409,8 +413,7 @@ type WalletController interface {
//
// NOTE: This method requires the global coin selection lock to be held.
LeaseOutput(id wtxmgr.LockID, op wire.OutPoint,
duration time.Duration) (time.Time, []byte, btcutil.Amount,
error)
duration time.Duration) (time.Time, error)

// ReleaseOutput unlocks an output, allowing it to be available for coin
// selection if it remains unspent. The ID should match the one used to
Expand Down
16 changes: 12 additions & 4 deletions lnwallet/mock.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,9 +45,9 @@ func (w *mockWalletController) BackEnd() string {
return "mock"
}

// FetchInputInfo will be called to get info about the inputs to the funding
// FetchOutpointInfo will be called to get info about the inputs to the funding
// transaction.
func (w *mockWalletController) FetchInputInfo(
func (w *mockWalletController) FetchOutpointInfo(
prevOut *wire.OutPoint) (*Utxo, error) {

utxo := &Utxo{
Expand Down Expand Up @@ -201,9 +201,9 @@ func (w *mockWalletController) ListTransactionDetails(int32, int32,

// LeaseOutput returns the current time and a nil error.
func (w *mockWalletController) LeaseOutput(wtxmgr.LockID, wire.OutPoint,
time.Duration) (time.Time, []byte, btcutil.Amount, error) {
time.Duration) (time.Time, error) {

return time.Now(), nil, 0, nil
return time.Now(), nil
}

// ReleaseOutput currently does nothing.
Expand Down Expand Up @@ -300,6 +300,14 @@ func (w *mockWalletController) RemoveDescendants(*wire.MsgTx) error {
return nil
}

// FetchDerivationInfo queries for the wallet's knowledge of the passed
// pkScript and constructs the derivation info and returns it.
func (w *mockWalletController) FetchDerivationInfo(
pkScript []byte) (*psbt.Bip32Derivation, error) {

return nil, nil
}

func (w *mockWalletController) CheckMempoolAcceptance(tx *wire.MsgTx) error {
return nil
}
Expand Down
Loading
Loading