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

lnd: use change output index from authoring TX to check reserved value #5665

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions docs/release-notes/release-notes-0.14.0.md
Original file line number Diff line number Diff line change
Expand Up @@ -405,6 +405,9 @@ you.
[Lnd is updated to use the version of Neutrino containing this
fix](https://github.com/lightningnetwork/lnd/pull/5807).

* [Use the change output index when validating the reserved wallet balance for
SendCoins/SendMany calls](https://github.com/lightningnetwork/lnd/pull/5665)

## Documentation

The [code contribution guidelines have been updated to mention the new
Expand Down
55 changes: 51 additions & 4 deletions lnwallet/wallet.go
Original file line number Diff line number Diff line change
Expand Up @@ -272,6 +272,20 @@ type addSingleFunderSigsMsg struct {
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
// executing workflow required to interact with the Lightning Network. It is
// domain specific in the sense that it understands all the fancy scripts used
Expand Down Expand Up @@ -1036,20 +1050,53 @@ func (l *LightningWallet) CheckReservedValue(in []wire.OutPoint,
// database.
//
// NOTE: This method should only be run with the CoinSelectLock held.
func (l *LightningWallet) CheckReservedValueTx(tx *wire.MsgTx) (btcutil.Amount,
error) {
func (l *LightningWallet) CheckReservedValueTx(req CheckReservedValueTxReq) (
btcutil.Amount, error) {

numAnchors, err := l.currentNumAnchorChans()
if err != nil {
return 0, err
}

var inputs []wire.OutPoint
for _, txIn := range tx.TxIn {
for _, txIn := range req.Tx.TxIn {
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
Expand Down
17 changes: 14 additions & 3 deletions rpcserver.go
Original file line number Diff line number Diff line change
Expand Up @@ -1009,7 +1009,14 @@ func (r *rpcServer) sendCoinsOnChain(paymentMap map[string]int64,
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 {
return nil, err
}
Expand Down Expand Up @@ -1242,7 +1249,9 @@ func (r *rpcServer) SendCoins(ctx context.Context,
err = wallet.WithCoinSelectLock(func() error {
var err error
reservedVal, err = wallet.CheckReservedValueTx(
sweepTxPkg.SweepTx,
lnwallet.CheckReservedValueTxReq{
Tx: sweepTxPkg.SweepTx,
},
)
return err
})
Expand Down Expand Up @@ -1292,7 +1301,9 @@ func (r *rpcServer) SendCoins(ctx context.Context,
// Sanity check the new tx by re-doing the check.
err = wallet.WithCoinSelectLock(func() error {
_, err := wallet.CheckReservedValueTx(
sweepTxPkg.SweepTx,
lnwallet.CheckReservedValueTxReq{
Tx: sweepTxPkg.SweepTx,
},
)
return err
})
Expand Down