multi: switch to transaction weight to calculate transaction fees

Due to a recent change within the codebase to return estimated fee rates
in sat/kw, this commit ensures that we use this fee rate properly by
calculing a transaction's fees using its weight. This includes all of
the different transactions that are created within lnd (funding, sweeps,
etc.). On-chain transactions still rely on a sat/vbyte fee rate since it's
required by btcwallet.
This commit is contained in:
Wilmer Paulino 2018-07-27 18:27:51 -07:00
parent b3d5d7ab9c
commit a63677a381
No known key found for this signature in database
GPG Key ID: 6DF57B9F9514972F
4 changed files with 48 additions and 47 deletions

View File

@ -1015,13 +1015,13 @@ func (b *breachArbiter) createJusticeTx(
spendableOutputs = append(spendableOutputs, input)
}
txVSize := int64(weightEstimate.VSize())
return b.sweepSpendableOutputsTxn(txVSize, spendableOutputs...)
txWeight := int64(weightEstimate.Weight())
return b.sweepSpendableOutputsTxn(txWeight, spendableOutputs...)
}
// sweepSpendableOutputsTxn creates a signed transaction from a sequence of
// spendable outputs by sweeping the funds into a single p2wkh output.
func (b *breachArbiter) sweepSpendableOutputsTxn(txVSize int64,
func (b *breachArbiter) sweepSpendableOutputsTxn(txWeight int64,
inputs ...SpendableOutput) (*wire.MsgTx, error) {
// First, we obtain a new public key script from the wallet which we'll
@ -1041,11 +1041,11 @@ func (b *breachArbiter) sweepSpendableOutputsTxn(txVSize int64,
// We'll actually attempt to target inclusion within the next two
// blocks as we'd like to sweep these funds back into our wallet ASAP.
feePerVSize, err := b.cfg.Estimator.EstimateFeePerVSize(2)
feePerKw, err := b.cfg.Estimator.EstimateFeePerKW(2)
if err != nil {
return nil, err
}
txFee := feePerVSize.FeeForVSize(txVSize)
txFee := feePerKw.FeeForWeight(txWeight)
// TODO(roasbeef): already start to siphon their funds into fees
sweepAmt := int64(totalAmt - txFee)

View File

@ -451,27 +451,27 @@ func (h *htlcSuccessResolver) Resolve() (ContractResolver, error) {
return nil, err
}
// With out address obtained, we'll query for an
// With our address obtained, we'll query for an
// estimate to be confirmed at ease.
//
// TODO(roasbeef): signal up if fee would be too large
// to sweep singly, need to batch
feePerVSize, err := h.FeeEstimator.EstimateFeePerVSize(6)
feePerKw, err := h.FeeEstimator.EstimateFeePerKW(6)
if err != nil {
return nil, err
}
log.Debugf("%T(%x): using %v sat/vbyte to sweep htlc"+
log.Debugf("%T(%x): using %v sat/kw to sweep htlc"+
"incoming+remote htlc confirmed", h,
h.payHash[:], int64(feePerVSize))
h.payHash[:], int64(feePerKw))
// Using a weight estimator, we'll compute the total
// fee required, and from that the value we'll end up
// with.
totalVSize := (&lnwallet.TxWeightEstimator{}).
totalWeight := (&lnwallet.TxWeightEstimator{}).
AddWitnessInput(lnwallet.OfferedHtlcSuccessWitnessSize).
AddP2WKHOutput().VSize()
totalFees := feePerVSize.FeeForVSize(int64(totalVSize))
AddP2WKHOutput().Weight()
totalFees := feePerKw.FeeForWeight(int64(totalWeight))
sweepAmt := h.htlcResolution.SweepSignDesc.Output.Value -
int64(totalFees)
@ -1253,18 +1253,18 @@ func (c *commitSweepResolver) Resolve() (ContractResolver, error) {
// First, we'll estimate the total weight so we can compute
// fees properly. We'll use a lax estimate, as this output is
// in no immediate danger.
feePerVSize, err := c.FeeEstimator.EstimateFeePerVSize(6)
feePerKw, err := c.FeeEstimator.EstimateFeePerKW(6)
if err != nil {
return nil, err
}
log.Debugf("%T(%v): using %v sat/vsize for sweep tx", c,
c.chanPoint, int64(feePerVSize))
log.Debugf("%T(%v): using %v sat/kw for sweep tx", c,
c.chanPoint, int64(feePerKw))
totalVSize := (&lnwallet.TxWeightEstimator{}).
AddP2PKHInput().
AddP2WKHOutput().VSize()
totalFees := feePerVSize.FeeForVSize(int64(totalVSize))
totalWeight := (&lnwallet.TxWeightEstimator{}).
AddP2WKHInput().
AddP2WKHOutput().Weight()
totalFees := feePerKw.FeeForWeight(int64(totalWeight))
sweepAmt := signDesc.Output.Value - int64(totalFees)
c.sweepTx = wire.NewMsgTx(2)

View File

@ -81,9 +81,9 @@ type initFundingReserveMsg struct {
// paying some multiple of the accepted base fee rate of the network.
commitFeePerKw SatPerKWeight
// fundingFeePerVSize is the fee rate in sat/vbyte to use for the
// initial funding transaction.
fundingFeePerVSize SatPerVByte
// fundingFeePerKw is the fee rate in sat/kw to use for the initial
// funding transaction.
fundingFeePerKw SatPerKWeight
// pushMSat is the number of milli-satoshis that should be pushed over
// the responder as part of the initial channel creation.
@ -413,7 +413,7 @@ out:
// commitment transaction is valid.
func (l *LightningWallet) InitChannelReservation(
capacity, ourFundAmt btcutil.Amount, pushMSat lnwire.MilliSatoshi,
commitFeePerKw SatPerKWeight, fundingFeePerVSize SatPerVByte,
commitFeePerKw SatPerKWeight, fundingFeePerKw SatPerKWeight,
theirID *btcec.PublicKey, theirAddr net.Addr,
chainHash *chainhash.Hash, flags lnwire.FundingFlag) (*ChannelReservation, error) {
@ -421,17 +421,17 @@ func (l *LightningWallet) InitChannelReservation(
respChan := make(chan *ChannelReservation, 1)
l.msgChan <- &initFundingReserveMsg{
chainHash: chainHash,
nodeID: theirID,
nodeAddr: theirAddr,
fundingAmount: ourFundAmt,
capacity: capacity,
commitFeePerKw: commitFeePerKw,
fundingFeePerVSize: fundingFeePerVSize,
pushMSat: pushMSat,
flags: flags,
err: errChan,
resp: respChan,
chainHash: chainHash,
nodeID: theirID,
nodeAddr: theirAddr,
fundingAmount: ourFundAmt,
capacity: capacity,
commitFeePerKw: commitFeePerKw,
fundingFeePerKw: fundingFeePerKw,
pushMSat: pushMSat,
flags: flags,
err: errChan,
resp: respChan,
}
return <-respChan, <-errChan
@ -479,10 +479,10 @@ func (l *LightningWallet) handleFundingReserveRequest(req *initFundingReserveMsg
// don't need to perform any coin selection. Otherwise, attempt to
// obtain enough coins to meet the required funding amount.
if req.fundingAmount != 0 {
// Coin selection is done on the basis of sat-per-vbyte, we'll
// use the passed sat/vbyte passed in to perform coin selection.
// Coin selection is done on the basis of sat/kw, so we'll use
// the fee rate passed in to perform coin selection.
err := l.selectCoinsAndChange(
req.fundingFeePerVSize, req.fundingAmount,
req.fundingFeePerKw, req.fundingAmount,
reservation.ourContribution,
)
if err != nil {
@ -1276,7 +1276,7 @@ func (l *LightningWallet) handleSingleFunderSigs(req *addSingleFunderSigsMsg) {
// within the passed contribution's inputs. If necessary, a change address will
// also be generated.
// TODO(roasbeef): remove hardcoded fees and req'd confs for outputs.
func (l *LightningWallet) selectCoinsAndChange(feeRate SatPerVByte,
func (l *LightningWallet) selectCoinsAndChange(feeRate SatPerKWeight,
amt btcutil.Amount, contribution *ChannelContribution) error {
// We hold the coin select mutex while querying for outputs, and
@ -1286,7 +1286,7 @@ func (l *LightningWallet) selectCoinsAndChange(feeRate SatPerVByte,
defer l.coinSelectMtx.Unlock()
walletLog.Infof("Performing funding tx coin selection using %v "+
"sat/vbyte as fee rate", int64(feeRate))
"sat/kw as fee rate", int64(feeRate))
// Find all unlocked unspent witness outputs with greater than 1
// confirmation.
@ -1395,9 +1395,9 @@ func selectInputs(amt btcutil.Amount, coins []*Utxo) (btcutil.Amount, []*Utxo, e
// coinSelect attempts to select a sufficient amount of coins, including a
// change output to fund amt satoshis, adhering to the specified fee rate. The
// specified fee rate should be expressed in sat/vbyte for coin selection to
// specified fee rate should be expressed in sat/kw for coin selection to
// function properly.
func coinSelect(feeRate SatPerVByte, amt btcutil.Amount,
func coinSelect(feeRate SatPerKWeight, amt btcutil.Amount,
coins []*Utxo) ([]*Utxo, btcutil.Amount, error) {
amtNeeded := amt
@ -1441,7 +1441,8 @@ func coinSelect(feeRate SatPerVByte, amt btcutil.Amount,
// amount isn't enough to pay fees, then increase the requested
// coin amount by the estimate required fee, performing another
// round of coin selection.
requiredFee := feeRate.FeeForVSize(int64(weightEstimate.VSize()))
totalWeight := int64(weightEstimate.Weight())
requiredFee := feeRate.FeeForWeight(totalWeight)
if overShootAmt < requiredFee {
amtNeeded = amt + requiredFee
continue

View File

@ -994,15 +994,15 @@ func (u *utxoNursery) createSweepTx(kgtnOutputs []kidOutput,
utxnLog.Infof("Creating sweep transaction for %v CSV inputs, %v CLTV "+
"inputs", len(csvOutputs), len(cltvOutputs))
txVSize := int64(weightEstimate.VSize())
return u.populateSweepTx(txVSize, classHeight, csvOutputs, cltvOutputs)
txWeight := int64(weightEstimate.Weight())
return u.populateSweepTx(txWeight, classHeight, csvOutputs, cltvOutputs)
}
// populateSweepTx populate the final sweeping transaction with all witnesses
// in place for all inputs using the provided txn fee. The created transaction
// has a single output sending all the funds back to the source wallet, after
// accounting for the fee estimate.
func (u *utxoNursery) populateSweepTx(txVSize int64, classHeight uint32,
func (u *utxoNursery) populateSweepTx(txWeight int64, classHeight uint32,
csvInputs []CsvSpendableOutput,
cltvInputs []SpendableOutput) (*wire.MsgTx, error) {
@ -1022,11 +1022,11 @@ func (u *utxoNursery) populateSweepTx(txVSize int64, classHeight uint32,
}
// Using the txn weight estimate, compute the required txn fee.
feePerVSize, err := u.cfg.Estimator.EstimateFeePerVSize(6)
feePerKw, err := u.cfg.Estimator.EstimateFeePerKW(6)
if err != nil {
return nil, err
}
txFee := feePerVSize.FeeForVSize(txVSize)
txFee := feePerKw.FeeForWeight(txWeight)
// Sweep as much possible, after subtracting txn fees.
sweepAmt := int64(totalSum - txFee)