Skip to content

Commit

Permalink
Merge pull request #8961 from yyforyongyu/fix-leaseoutput
Browse files Browse the repository at this point in the history
Improve the performace of `LeaseOutput`
  • Loading branch information
Roasbeef authored Aug 21, 2024
2 parents a028064 + 363e529 commit cc9e2b7
Show file tree
Hide file tree
Showing 20 changed files with 100 additions and 87 deletions.
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 @@ -159,6 +159,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)
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 @@ -496,7 +496,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 @@ -1296,7 +1296,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

0 comments on commit cc9e2b7

Please sign in to comment.