Merge pull request #8961 from yyforyongyu/fix-leaseoutput

Improve the performace of `LeaseOutput`
This commit is contained in:
Olaoluwa Osuntokun authored and GitHub committed 2024-08-21 16:31:26 -07:00
commit cc9e2b783e
20 files changed
+100 -87

No files matched your search

+4 -20
View File
@@ -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.
+12 -6
View File
@@ -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"
@@ -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
}
@@ -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.
+1 -1
View File
@@ -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.
+1 -1
View File
@@ -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,
)
+12 -9
View File
@@ -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.
@@ -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
@@ -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
+12 -4
View File
@@ -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{
@@ -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.
@@ -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
}
+19 -6
View File
@@ -154,7 +154,7 @@ func (r *RPCKeyRing) SendOutputs(inputs fn.Set[wire.OutPoint],
// watch-only wallet if it can map this outpoint into a coin we
// own. If not, then we can't continue because our wallet state
// is out of sync.
info, err := r.WalletController.FetchInputInfo(
info, err := r.WalletController.FetchOutpointInfo(
&txIn.PreviousOutPoint,
)
if err != nil {
@@ -289,7 +289,7 @@ func (r *RPCKeyRing) FinalizePsbt(packet *psbt.Packet, _ string) error {
// We can only sign this input if it's ours, so we try to map it
// to a coin we own. If we can't, then we'll continue as it
// isn't our input.
utxo, err := r.FetchInputInfo(&txIn.PreviousOutPoint)
utxo, err := r.FetchOutpointInfo(&txIn.PreviousOutPoint)
if err != nil {
continue
}
@@ -906,7 +906,7 @@ func (r *RPCKeyRing) remoteSign(tx *wire.MsgTx, signDesc *input.SignDescriptor,
}
txIn := tx.TxIn[idx]
info, err := r.WalletController.FetchInputInfo(
info, err := r.WalletController.FetchOutpointInfo(
&txIn.PreviousOutPoint,
)
if err != nil {
@@ -1015,19 +1015,32 @@ func (r *RPCKeyRing) remoteSign(tx *wire.MsgTx, signDesc *input.SignDescriptor,
signDesc.KeyDesc.PubKey = fullDesc.PubKey
}
var derivation *psbt.Bip32Derivation
// Make sure we actually know about the input. We either have been
// watching the UTXO on-chain or we have been given all the required
// info in the sign descriptor.
info, err := r.WalletController.FetchInputInfo(&txIn.PreviousOutPoint)
info, err := r.WalletController.FetchOutpointInfo(
&txIn.PreviousOutPoint,
)
// If the wallet is aware of this outpoint, we go ahead and fetch the
// derivation info.
if err == nil {
derivation, err = r.WalletController.FetchDerivationInfo(
info.PkScript,
)
}
switch {
// No error, we do have the full UTXO and derivation info available.
// No error, we do have the full UTXO info available.
case err == nil:
in.WitnessUtxo = &wire.TxOut{
Value: int64(info.Value),
PkScript: info.PkScript,
}
in.NonWitnessUtxo = info.PrevTx
in.Bip32Derivation = []*psbt.Bip32Derivation{info.Derivation}
in.Bip32Derivation = []*psbt.Bip32Derivation{derivation}
// The wallet doesn't know about this UTXO, so it's probably a TX that
// we haven't published yet (e.g. a channel funding TX). So we need to
+3 -3
View File
@@ -1646,7 +1646,7 @@ func (l *LightningWallet) handleContributionMsg(req *addContributionMsg) {
[]*input.Script, 0, len(ourContribution.Inputs),
)
for _, txIn := range fundingTx.TxIn {
_, err := l.FetchInputInfo(&txIn.PreviousOutPoint)
_, err := l.FetchOutpointInfo(&txIn.PreviousOutPoint)
if err != nil {
continue
}
@@ -2592,7 +2592,7 @@ func (c *CoinSource) ListCoins(minConfs int32,
// its outpoint. If the coin isn't under the control of the backing CoinSource,
// then an error should be returned.
func (c *CoinSource) CoinFromOutPoint(op wire.OutPoint) (*wallet.Coin, error) {
inputInfo, err := c.wallet.FetchInputInfo(&op)
inputInfo, err := c.wallet.FetchOutpointInfo(&op)
if err != nil {
return nil, err
}
@@ -2689,7 +2689,7 @@ func NewWalletPrevOutputFetcher(wc WalletController) *WalletPrevOutputFetcher {
// passed outpoint. A nil value will be returned if the passed outpoint doesn't
// exist.
func (w *WalletPrevOutputFetcher) FetchPrevOutput(op wire.OutPoint) *wire.TxOut {
utxo, err := w.wc.FetchInputInfo(&op)
utxo, err := w.wc.FetchOutpointInfo(&op)
if err != nil {
return nil
}