mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-07-02 03:22:25 +02:00
lnd: add optional change output index to check reserved wallet balance
This commit is contained in:
@ -272,6 +272,20 @@ type addSingleFunderSigsMsg struct {
|
|||||||
err chan error
|
err chan error
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CheckReservedValueTxReq is the request struct used to call
|
||||||
|
// CheckReservedValueTx with. It contains the transaction to check as well as
|
||||||
|
// an optional explicitly defined index to denote a change output that is not
|
||||||
|
// watched by the wallet.
|
||||||
|
type CheckReservedValueTxReq struct {
|
||||||
|
// Tx is the transaction to check the outputs for.
|
||||||
|
Tx *wire.MsgTx
|
||||||
|
|
||||||
|
// ChangeIndex denotes an optional output index that can be explicitly
|
||||||
|
// set for a change that is not being watched by the wallet and would
|
||||||
|
// otherwise not be recognized as a change output.
|
||||||
|
ChangeIndex *int
|
||||||
|
}
|
||||||
|
|
||||||
// LightningWallet is a domain specific, yet general Bitcoin wallet capable of
|
// LightningWallet is a domain specific, yet general Bitcoin wallet capable of
|
||||||
// executing workflow required to interact with the Lightning Network. It is
|
// executing workflow required to interact with the Lightning Network. It is
|
||||||
// domain specific in the sense that it understands all the fancy scripts used
|
// domain specific in the sense that it understands all the fancy scripts used
|
||||||
@ -1036,8 +1050,8 @@ func (l *LightningWallet) CheckReservedValue(in []wire.OutPoint,
|
|||||||
// database.
|
// database.
|
||||||
//
|
//
|
||||||
// NOTE: This method should only be run with the CoinSelectLock held.
|
// NOTE: This method should only be run with the CoinSelectLock held.
|
||||||
func (l *LightningWallet) CheckReservedValueTx(tx *wire.MsgTx) (btcutil.Amount,
|
func (l *LightningWallet) CheckReservedValueTx(req CheckReservedValueTxReq) (
|
||||||
error) {
|
btcutil.Amount, error) {
|
||||||
|
|
||||||
numAnchors, err := l.currentNumAnchorChans()
|
numAnchors, err := l.currentNumAnchorChans()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
@ -1045,11 +1059,44 @@ func (l *LightningWallet) CheckReservedValueTx(tx *wire.MsgTx) (btcutil.Amount,
|
|||||||
}
|
}
|
||||||
|
|
||||||
var inputs []wire.OutPoint
|
var inputs []wire.OutPoint
|
||||||
for _, txIn := range tx.TxIn {
|
for _, txIn := range req.Tx.TxIn {
|
||||||
inputs = append(inputs, txIn.PreviousOutPoint)
|
inputs = append(inputs, txIn.PreviousOutPoint)
|
||||||
}
|
}
|
||||||
|
|
||||||
return l.CheckReservedValue(inputs, tx.TxOut, numAnchors)
|
reservedVal, err := l.CheckReservedValue(
|
||||||
|
inputs, req.Tx.TxOut, numAnchors,
|
||||||
|
)
|
||||||
|
switch {
|
||||||
|
|
||||||
|
// If the error returned from CheckReservedValue is
|
||||||
|
// ErrReservedValueInvalidated, then it did nonetheless return
|
||||||
|
// the required reserved value and we check for the optional
|
||||||
|
// change index.
|
||||||
|
case errors.Is(err, ErrReservedValueInvalidated):
|
||||||
|
// Without a change index provided there is nothing more to
|
||||||
|
// check and the error is returned.
|
||||||
|
if req.ChangeIndex == nil {
|
||||||
|
return reservedVal, err
|
||||||
|
}
|
||||||
|
|
||||||
|
// If a change index was provided we make only sure that it
|
||||||
|
// would leave sufficient funds for the reserved balance value.
|
||||||
|
//
|
||||||
|
// Note: This is used if a change output index is explicitly set
|
||||||
|
// but that may not be watched by the wallet and therefore is
|
||||||
|
// not picked up by the call to CheckReservedValue above.
|
||||||
|
chIdx := *req.ChangeIndex
|
||||||
|
if chIdx < 0 || chIdx >= len(req.Tx.TxOut) ||
|
||||||
|
req.Tx.TxOut[chIdx].Value < int64(reservedVal) {
|
||||||
|
|
||||||
|
return reservedVal, err
|
||||||
|
}
|
||||||
|
|
||||||
|
case err != nil:
|
||||||
|
return reservedVal, err
|
||||||
|
}
|
||||||
|
|
||||||
|
return reservedVal, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// initOurContribution initializes the given ChannelReservation with our coins
|
// initOurContribution initializes the given ChannelReservation with our coins
|
||||||
|
17
rpcserver.go
17
rpcserver.go
@ -1009,7 +1009,14 @@ func (r *rpcServer) sendCoinsOnChain(paymentMap map[string]int64,
|
|||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
_, err = r.server.cc.Wallet.CheckReservedValueTx(authoredTx.Tx)
|
// Check the authored transaction and use the explicitly set change index
|
||||||
|
// to make sure that the wallet reserved balance is not invalidated.
|
||||||
|
_, err = r.server.cc.Wallet.CheckReservedValueTx(
|
||||||
|
lnwallet.CheckReservedValueTxReq{
|
||||||
|
Tx: authoredTx.Tx,
|
||||||
|
ChangeIndex: &authoredTx.ChangeIndex,
|
||||||
|
},
|
||||||
|
)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
@ -1242,7 +1249,9 @@ func (r *rpcServer) SendCoins(ctx context.Context,
|
|||||||
err = wallet.WithCoinSelectLock(func() error {
|
err = wallet.WithCoinSelectLock(func() error {
|
||||||
var err error
|
var err error
|
||||||
reservedVal, err = wallet.CheckReservedValueTx(
|
reservedVal, err = wallet.CheckReservedValueTx(
|
||||||
sweepTxPkg.SweepTx,
|
lnwallet.CheckReservedValueTxReq{
|
||||||
|
Tx: sweepTxPkg.SweepTx,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
return err
|
return err
|
||||||
})
|
})
|
||||||
@ -1292,7 +1301,9 @@ func (r *rpcServer) SendCoins(ctx context.Context,
|
|||||||
// Sanity check the new tx by re-doing the check.
|
// Sanity check the new tx by re-doing the check.
|
||||||
err = wallet.WithCoinSelectLock(func() error {
|
err = wallet.WithCoinSelectLock(func() error {
|
||||||
_, err := wallet.CheckReservedValueTx(
|
_, err := wallet.CheckReservedValueTx(
|
||||||
sweepTxPkg.SweepTx,
|
lnwallet.CheckReservedValueTxReq{
|
||||||
|
Tx: sweepTxPkg.SweepTx,
|
||||||
|
},
|
||||||
)
|
)
|
||||||
return err
|
return err
|
||||||
})
|
})
|
||||||
|
Reference in New Issue
Block a user