Skip to content

Commit ab7634b

Browse files
committed
multi: Add utxo restriction for batchchannel openings.
Add utxo restrictions for psbt internal wallet funded lightning channels. This also includes batchopening channels backed by the internal wallet.
1 parent 62a52b4 commit ab7634b

File tree

5 files changed

+79
-7
lines changed

5 files changed

+79
-7
lines changed

lnrpc/walletrpc/walletkit_server.go

Lines changed: 64 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1551,21 +1551,82 @@ func (w *WalletKit) fundPsbtInternalWallet(account string,
15511551
return err
15521552
}
15531553

1554+
// filterFn makes sure utxos which are unconfirmed and
1555+
// still used by the sweeper are not used.
1556+
filterFn := func(u *lnwallet.Utxo) bool {
1557+
// Confirmed utxos are always allowed.
1558+
if u.Confirmations > 0 {
1559+
return true
1560+
}
1561+
1562+
// Unconfirmed utxos in use by the sweeper are
1563+
// not stable to use because they can be
1564+
// replaced.
1565+
if w.cfg.Sweeper.IsSweeperOutpoint(u.OutPoint) {
1566+
log.Warnf("Cannot use unconfirmed "+
1567+
"utxo=%v because it is "+
1568+
"unstable and could be "+
1569+
"replaced", u.OutPoint)
1570+
1571+
return false
1572+
}
1573+
1574+
return true
1575+
}
1576+
1577+
eligible := fn.Filter(filterFn, utxos)
1578+
15541579
// Validate all inputs against our known list of UTXOs
15551580
// now.
1556-
err = verifyInputsUnspent(packet.UnsignedTx.TxIn, utxos)
1581+
err = verifyInputsUnspent(
1582+
packet.UnsignedTx.TxIn, eligible,
1583+
)
15571584
if err != nil {
15581585
return err
15591586
}
15601587
}
15611588

1589+
// currentHeight is needed to determine whether the internal
1590+
// wallet utxo is still unconfirmed.
1591+
_, currentHeight, err := w.cfg.Chain.GetBestBlock()
1592+
if err != nil {
1593+
return fmt.Errorf("unable to retrieve current "+
1594+
"height: %v", err)
1595+
}
1596+
1597+
// restrictUnstableUtxos is a filter function which disallows
1598+
// the usage of unconfirmed outputs published (still in use) by
1599+
// the sweeper.
1600+
restrictUnstableUtxos := func(utxo wtxmgr.Credit) bool {
1601+
// Wallet utxos which are unmined have a height
1602+
// of -1.
1603+
if utxo.Height != -1 && utxo.Height <= currentHeight {
1604+
// Confirmed utxos are always allowed.
1605+
return true
1606+
}
1607+
1608+
// Utxos used by the sweeper are not used for
1609+
// channel openings.
1610+
allowed := !w.cfg.Sweeper.IsSweeperOutpoint(
1611+
utxo.OutPoint,
1612+
)
1613+
if !allowed {
1614+
log.Warnf("Cannot use unconfirmed "+
1615+
"utxo=%v because it is "+
1616+
"unstable and could be "+
1617+
"replaced", utxo.OutPoint)
1618+
}
1619+
1620+
return allowed
1621+
}
1622+
15621623
// We made sure the input from the user is as sane as possible.
15631624
// We can now ask the wallet to fund the TX. This will not yet
15641625
// lock any coins but might still change the wallet DB by
15651626
// generating a new change address.
15661627
changeIndex, err := w.cfg.Wallet.FundPsbt(
1567-
packet, minConfs, feeSatPerKW, account,
1568-
keyScope, strategy,
1628+
packet, minConfs, feeSatPerKW, account, keyScope,
1629+
strategy, restrictUnstableUtxos,
15691630
)
15701631
if err != nil {
15711632
return fmt.Errorf("wallet couldn't fund PSBT: %w", err)

lntest/mock/walletcontroller.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -208,7 +208,8 @@ func (w *WalletController) ListLeasedOutputs() ([]*base.ListLeasedOutputResult,
208208

209209
// FundPsbt currently does nothing.
210210
func (w *WalletController) FundPsbt(*psbt.Packet, int32, chainfee.SatPerKWeight,
211-
string, *waddrmgr.KeyScope, base.CoinSelectionStrategy) (int32, error) {
211+
string, *waddrmgr.KeyScope, base.CoinSelectionStrategy,
212+
func(utxo wtxmgr.Credit) bool) (int32, error) {
212213

213214
return 0, nil
214215
}

lnwallet/btcwallet/psbt.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"github.com/btcsuite/btcd/wire"
1616
"github.com/btcsuite/btcwallet/waddrmgr"
1717
"github.com/btcsuite/btcwallet/wallet"
18+
"github.com/btcsuite/btcwallet/wtxmgr"
1819
"github.com/lightningnetwork/lnd/input"
1920
"github.com/lightningnetwork/lnd/keychain"
2021
"github.com/lightningnetwork/lnd/lnwallet"
@@ -60,6 +61,9 @@ var (
6061
// imported public keys. For custom account, no key scope should be provided
6162
// as the coin selection key scope will always be used to generate the change
6263
// address.
64+
// The function argument `allowUtxo` specifies a filter function for utxos
65+
// during coin selection. It should return true for utxos that can be used and
66+
// false for those that should be excluded.
6367
//
6468
// NOTE: If the packet doesn't contain any inputs, coin selection is performed
6569
// automatically. The account parameter must be non-empty as it determines which
@@ -74,7 +78,8 @@ var (
7478
func (b *BtcWallet) FundPsbt(packet *psbt.Packet, minConfs int32,
7579
feeRate chainfee.SatPerKWeight, accountName string,
7680
changeScope *waddrmgr.KeyScope,
77-
strategy wallet.CoinSelectionStrategy) (int32, error) {
81+
strategy wallet.CoinSelectionStrategy,
82+
allowUtxo func(wtxmgr.Credit) bool) (int32, error) {
7883

7984
// The fee rate is passed in using units of sat/kw, so we'll convert
8085
// this to sat/KB as the CreateSimpleTx method requires this unit.
@@ -130,6 +135,9 @@ func (b *BtcWallet) FundPsbt(packet *psbt.Packet, minConfs int32,
130135
if changeScope != nil {
131136
opts = append(opts, wallet.WithCustomChangeScope(changeScope))
132137
}
138+
if allowUtxo != nil {
139+
opts = append(opts, wallet.WithUtxoFilter(allowUtxo))
140+
}
133141

134142
// Let the wallet handle coin selection and/or fee estimation based on
135143
// the partial TX information in the packet.

lnwallet/interface.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -468,7 +468,8 @@ type WalletController interface {
468468
FundPsbt(packet *psbt.Packet, minConfs int32,
469469
feeRate chainfee.SatPerKWeight, account string,
470470
changeScope *waddrmgr.KeyScope,
471-
strategy base.CoinSelectionStrategy) (int32, error)
471+
strategy base.CoinSelectionStrategy,
472+
allowUtxo func(wtxmgr.Credit) bool) (int32, error)
472473

473474
// SignPsbt expects a partial transaction with all inputs and outputs
474475
// fully declared and tries to sign all unsigned inputs that have all

lnwallet/mock.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -217,7 +217,8 @@ func (w *mockWalletController) ListLeasedOutputs() (
217217
// FundPsbt currently does nothing.
218218
func (w *mockWalletController) FundPsbt(*psbt.Packet, int32,
219219
chainfee.SatPerKWeight, string, *waddrmgr.KeyScope,
220-
base.CoinSelectionStrategy) (int32, error) {
220+
base.CoinSelectionStrategy, func(utxo wtxmgr.Credit) bool) (int32,
221+
error) {
221222

222223
return 0, nil
223224
}

0 commit comments

Comments
 (0)