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:
parent
b3d5d7ab9c
commit
a63677a381
@ -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)
|
||||
|
@ -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)
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
Loading…
Reference in New Issue
Block a user