lnwallet/wallet: define SubtractFees for InitFundingReserveMsg

This commit adds a SubtractFees option to the funding request, letting
the caller specify that the fees should be deducted from the funding
amount. This paves the way for letting the funding manager spend up to a
given amount when creating a channel, like the rest of the funds in the
wallet.
This commit is contained in:
Johan T. Halseth 2019-07-11 13:14:37 +02:00
parent 4239f7d600
commit f15d81426c
No known key found for this signature in database
GPG Key ID: 15BAADA29DA20D26

@ -69,6 +69,13 @@ type InitFundingReserveMsg struct {
// workflow. // workflow.
NodeAddr net.Addr NodeAddr net.Addr
// SubtractFees should be set if we intend to spend exactly
// LocalFundingAmt when opening the channel, subtracting the fees from
// the funding output. This can be used for instance to use all our
// remaining funds to open the channel, since it will take fees into
// account.
SubtractFees bool
// LocalFundingAmt is the amount of funds requested from us for this // LocalFundingAmt is the amount of funds requested from us for this
// channel. // channel.
LocalFundingAmt btcutil.Amount LocalFundingAmt btcutil.Amount
@ -450,7 +457,6 @@ func (l *LightningWallet) handleFundingReserveRequest(req *InitFundingReserveMsg
return return
} }
capacity := req.LocalFundingAmt + req.RemoteFundingAmt
localFundingAmt := req.LocalFundingAmt localFundingAmt := req.LocalFundingAmt
var ( var (
@ -468,14 +474,21 @@ func (l *LightningWallet) handleFundingReserveRequest(req *InitFundingReserveMsg
var err error var err error
selected, err = l.selectCoinsAndChange( selected, err = l.selectCoinsAndChange(
req.FundingFeePerKw, req.LocalFundingAmt, req.MinConfs, req.FundingFeePerKw, req.LocalFundingAmt, req.MinConfs,
req.SubtractFees,
) )
if err != nil { if err != nil {
req.err <- err req.err <- err
req.resp <- nil req.resp <- nil
return return
} }
localFundingAmt = selected.fundingAmt
} }
// The total channel capacity will be the size of the funding output we
// created plus the remote contribution.
capacity := localFundingAmt + req.RemoteFundingAmt
id := atomic.AddUint64(&l.nextFundingID, 1) id := atomic.AddUint64(&l.nextFundingID, 1)
reservation, err := NewChannelReservation( reservation, err := NewChannelReservation(
capacity, localFundingAmt, req.CommitFeePerKw, l, id, capacity, localFundingAmt, req.CommitFeePerKw, l, id,
@ -1289,6 +1302,7 @@ func (l *LightningWallet) WithCoinSelectLock(f func() error) error {
type coinSelection struct { type coinSelection struct {
coins []*wire.TxIn coins []*wire.TxIn
change []*wire.TxOut change []*wire.TxOut
fundingAmt btcutil.Amount
unlockCoins func() unlockCoins func()
} }
@ -1296,10 +1310,12 @@ type coinSelection struct {
// outputs which sum to at least 'amt' amount of satoshis. If necessary, // outputs which sum to at least 'amt' amount of satoshis. If necessary,
// a change address will also be generated. If coin selection is // a change address will also be generated. If coin selection is
// successful/possible, then the selected coins and change outputs are // successful/possible, then the selected coins and change outputs are
// returned. This method locks the selected outputs, and a function closure to // returned, and the value of the resulting funding output. This method locks
// unlock them in case of an error is returned. // the selected outputs, and a function closure to unlock them in case of an
// error is returned.
func (l *LightningWallet) selectCoinsAndChange(feeRate SatPerKWeight, func (l *LightningWallet) selectCoinsAndChange(feeRate SatPerKWeight,
amt btcutil.Amount, minConfs int32) (*coinSelection, error) { amt btcutil.Amount, minConfs int32, subtractFees bool) (
*coinSelection, error) {
// We hold the coin select mutex while querying for outputs, and // We hold the coin select mutex while querying for outputs, and
// performing coin selection in order to avoid inadvertent double // performing coin selection in order to avoid inadvertent double
@ -1317,14 +1333,38 @@ func (l *LightningWallet) selectCoinsAndChange(feeRate SatPerKWeight,
return nil, err return nil, err
} }
var (
selectedCoins []*Utxo
fundingAmt btcutil.Amount
changeAmt btcutil.Amount
)
// Perform coin selection over our available, unlocked unspent outputs // Perform coin selection over our available, unlocked unspent outputs
// in order to find enough coins to meet the funding amount // in order to find enough coins to meet the funding amount
// requirements. // requirements.
selectedCoins, changeAmt, err := coinSelect(feeRate, amt, coins) switch {
// In case this request want the fees subtracted from the local amount,
// we'll call the specialized method for that. This ensures that we
// won't deduct more that the specified balance from our wallet.
case subtractFees:
dustLimit := l.Cfg.DefaultConstraints.DustLimit
selectedCoins, fundingAmt, changeAmt, err = coinSelectSubtractFees(
feeRate, amt, dustLimit, coins,
)
if err != nil { if err != nil {
return nil, err return nil, err
} }
// Ótherwise do a normal coin selection where we target a given funding
// amount.
default:
fundingAmt = amt
selectedCoins, changeAmt, err = coinSelect(feeRate, amt, coins)
if err != nil {
return nil, err
}
}
// Record any change output(s) generated as a result of the coin // Record any change output(s) generated as a result of the coin
// selection, but only if the addition of the output won't lead to the // selection, but only if the addition of the output won't lead to the
// creation of dust. // creation of dust.
@ -1374,6 +1414,7 @@ func (l *LightningWallet) selectCoinsAndChange(feeRate SatPerKWeight,
return &coinSelection{ return &coinSelection{
coins: inputs, coins: inputs,
change: changeOutputs, change: changeOutputs,
fundingAmt: fundingAmt,
unlockCoins: unlock, unlockCoins: unlock,
}, nil }, nil
} }