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)
|
spendableOutputs = append(spendableOutputs, input)
|
||||||
}
|
}
|
||||||
|
|
||||||
txVSize := int64(weightEstimate.VSize())
|
txWeight := int64(weightEstimate.Weight())
|
||||||
return b.sweepSpendableOutputsTxn(txVSize, spendableOutputs...)
|
return b.sweepSpendableOutputsTxn(txWeight, spendableOutputs...)
|
||||||
}
|
}
|
||||||
|
|
||||||
// sweepSpendableOutputsTxn creates a signed transaction from a sequence of
|
// sweepSpendableOutputsTxn creates a signed transaction from a sequence of
|
||||||
// spendable outputs by sweeping the funds into a single p2wkh output.
|
// 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) {
|
inputs ...SpendableOutput) (*wire.MsgTx, error) {
|
||||||
|
|
||||||
// First, we obtain a new public key script from the wallet which we'll
|
// 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
|
// 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.
|
// 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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
txFee := feePerVSize.FeeForVSize(txVSize)
|
txFee := feePerKw.FeeForWeight(txWeight)
|
||||||
|
|
||||||
// TODO(roasbeef): already start to siphon their funds into fees
|
// TODO(roasbeef): already start to siphon their funds into fees
|
||||||
sweepAmt := int64(totalAmt - txFee)
|
sweepAmt := int64(totalAmt - txFee)
|
||||||
|
@ -451,27 +451,27 @@ func (h *htlcSuccessResolver) Resolve() (ContractResolver, error) {
|
|||||||
return nil, err
|
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.
|
// estimate to be confirmed at ease.
|
||||||
//
|
//
|
||||||
// TODO(roasbeef): signal up if fee would be too large
|
// TODO(roasbeef): signal up if fee would be too large
|
||||||
// to sweep singly, need to batch
|
// to sweep singly, need to batch
|
||||||
feePerVSize, err := h.FeeEstimator.EstimateFeePerVSize(6)
|
feePerKw, err := h.FeeEstimator.EstimateFeePerKW(6)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
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,
|
"incoming+remote htlc confirmed", h,
|
||||||
h.payHash[:], int64(feePerVSize))
|
h.payHash[:], int64(feePerKw))
|
||||||
|
|
||||||
// Using a weight estimator, we'll compute the total
|
// Using a weight estimator, we'll compute the total
|
||||||
// fee required, and from that the value we'll end up
|
// fee required, and from that the value we'll end up
|
||||||
// with.
|
// with.
|
||||||
totalVSize := (&lnwallet.TxWeightEstimator{}).
|
totalWeight := (&lnwallet.TxWeightEstimator{}).
|
||||||
AddWitnessInput(lnwallet.OfferedHtlcSuccessWitnessSize).
|
AddWitnessInput(lnwallet.OfferedHtlcSuccessWitnessSize).
|
||||||
AddP2WKHOutput().VSize()
|
AddP2WKHOutput().Weight()
|
||||||
totalFees := feePerVSize.FeeForVSize(int64(totalVSize))
|
totalFees := feePerKw.FeeForWeight(int64(totalWeight))
|
||||||
sweepAmt := h.htlcResolution.SweepSignDesc.Output.Value -
|
sweepAmt := h.htlcResolution.SweepSignDesc.Output.Value -
|
||||||
int64(totalFees)
|
int64(totalFees)
|
||||||
|
|
||||||
@ -1253,18 +1253,18 @@ func (c *commitSweepResolver) Resolve() (ContractResolver, error) {
|
|||||||
// First, we'll estimate the total weight so we can compute
|
// First, we'll estimate the total weight so we can compute
|
||||||
// fees properly. We'll use a lax estimate, as this output is
|
// fees properly. We'll use a lax estimate, as this output is
|
||||||
// in no immediate danger.
|
// in no immediate danger.
|
||||||
feePerVSize, err := c.FeeEstimator.EstimateFeePerVSize(6)
|
feePerKw, err := c.FeeEstimator.EstimateFeePerKW(6)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
|
||||||
log.Debugf("%T(%v): using %v sat/vsize for sweep tx", c,
|
log.Debugf("%T(%v): using %v sat/kw for sweep tx", c,
|
||||||
c.chanPoint, int64(feePerVSize))
|
c.chanPoint, int64(feePerKw))
|
||||||
|
|
||||||
totalVSize := (&lnwallet.TxWeightEstimator{}).
|
totalWeight := (&lnwallet.TxWeightEstimator{}).
|
||||||
AddP2PKHInput().
|
AddP2WKHInput().
|
||||||
AddP2WKHOutput().VSize()
|
AddP2WKHOutput().Weight()
|
||||||
totalFees := feePerVSize.FeeForVSize(int64(totalVSize))
|
totalFees := feePerKw.FeeForWeight(int64(totalWeight))
|
||||||
sweepAmt := signDesc.Output.Value - int64(totalFees)
|
sweepAmt := signDesc.Output.Value - int64(totalFees)
|
||||||
|
|
||||||
c.sweepTx = wire.NewMsgTx(2)
|
c.sweepTx = wire.NewMsgTx(2)
|
||||||
|
@ -81,9 +81,9 @@ type initFundingReserveMsg struct {
|
|||||||
// paying some multiple of the accepted base fee rate of the network.
|
// paying some multiple of the accepted base fee rate of the network.
|
||||||
commitFeePerKw SatPerKWeight
|
commitFeePerKw SatPerKWeight
|
||||||
|
|
||||||
// fundingFeePerVSize is the fee rate in sat/vbyte to use for the
|
// fundingFeePerKw is the fee rate in sat/kw to use for the initial
|
||||||
// initial funding transaction.
|
// funding transaction.
|
||||||
fundingFeePerVSize SatPerVByte
|
fundingFeePerKw SatPerKWeight
|
||||||
|
|
||||||
// pushMSat is the number of milli-satoshis that should be pushed over
|
// pushMSat is the number of milli-satoshis that should be pushed over
|
||||||
// the responder as part of the initial channel creation.
|
// the responder as part of the initial channel creation.
|
||||||
@ -413,7 +413,7 @@ out:
|
|||||||
// commitment transaction is valid.
|
// commitment transaction is valid.
|
||||||
func (l *LightningWallet) InitChannelReservation(
|
func (l *LightningWallet) InitChannelReservation(
|
||||||
capacity, ourFundAmt btcutil.Amount, pushMSat lnwire.MilliSatoshi,
|
capacity, ourFundAmt btcutil.Amount, pushMSat lnwire.MilliSatoshi,
|
||||||
commitFeePerKw SatPerKWeight, fundingFeePerVSize SatPerVByte,
|
commitFeePerKw SatPerKWeight, fundingFeePerKw SatPerKWeight,
|
||||||
theirID *btcec.PublicKey, theirAddr net.Addr,
|
theirID *btcec.PublicKey, theirAddr net.Addr,
|
||||||
chainHash *chainhash.Hash, flags lnwire.FundingFlag) (*ChannelReservation, error) {
|
chainHash *chainhash.Hash, flags lnwire.FundingFlag) (*ChannelReservation, error) {
|
||||||
|
|
||||||
@ -421,17 +421,17 @@ func (l *LightningWallet) InitChannelReservation(
|
|||||||
respChan := make(chan *ChannelReservation, 1)
|
respChan := make(chan *ChannelReservation, 1)
|
||||||
|
|
||||||
l.msgChan <- &initFundingReserveMsg{
|
l.msgChan <- &initFundingReserveMsg{
|
||||||
chainHash: chainHash,
|
chainHash: chainHash,
|
||||||
nodeID: theirID,
|
nodeID: theirID,
|
||||||
nodeAddr: theirAddr,
|
nodeAddr: theirAddr,
|
||||||
fundingAmount: ourFundAmt,
|
fundingAmount: ourFundAmt,
|
||||||
capacity: capacity,
|
capacity: capacity,
|
||||||
commitFeePerKw: commitFeePerKw,
|
commitFeePerKw: commitFeePerKw,
|
||||||
fundingFeePerVSize: fundingFeePerVSize,
|
fundingFeePerKw: fundingFeePerKw,
|
||||||
pushMSat: pushMSat,
|
pushMSat: pushMSat,
|
||||||
flags: flags,
|
flags: flags,
|
||||||
err: errChan,
|
err: errChan,
|
||||||
resp: respChan,
|
resp: respChan,
|
||||||
}
|
}
|
||||||
|
|
||||||
return <-respChan, <-errChan
|
return <-respChan, <-errChan
|
||||||
@ -479,10 +479,10 @@ func (l *LightningWallet) handleFundingReserveRequest(req *initFundingReserveMsg
|
|||||||
// don't need to perform any coin selection. Otherwise, attempt to
|
// don't need to perform any coin selection. Otherwise, attempt to
|
||||||
// obtain enough coins to meet the required funding amount.
|
// obtain enough coins to meet the required funding amount.
|
||||||
if req.fundingAmount != 0 {
|
if req.fundingAmount != 0 {
|
||||||
// Coin selection is done on the basis of sat-per-vbyte, we'll
|
// Coin selection is done on the basis of sat/kw, so we'll use
|
||||||
// use the passed sat/vbyte passed in to perform coin selection.
|
// the fee rate passed in to perform coin selection.
|
||||||
err := l.selectCoinsAndChange(
|
err := l.selectCoinsAndChange(
|
||||||
req.fundingFeePerVSize, req.fundingAmount,
|
req.fundingFeePerKw, req.fundingAmount,
|
||||||
reservation.ourContribution,
|
reservation.ourContribution,
|
||||||
)
|
)
|
||||||
if err != nil {
|
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
|
// within the passed contribution's inputs. If necessary, a change address will
|
||||||
// also be generated.
|
// also be generated.
|
||||||
// TODO(roasbeef): remove hardcoded fees and req'd confs for outputs.
|
// 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 {
|
amt btcutil.Amount, contribution *ChannelContribution) error {
|
||||||
|
|
||||||
// We hold the coin select mutex while querying for outputs, and
|
// 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()
|
defer l.coinSelectMtx.Unlock()
|
||||||
|
|
||||||
walletLog.Infof("Performing funding tx coin selection using %v "+
|
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
|
// Find all unlocked unspent witness outputs with greater than 1
|
||||||
// confirmation.
|
// 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
|
// coinSelect attempts to select a sufficient amount of coins, including a
|
||||||
// change output to fund amt satoshis, adhering to the specified fee rate. The
|
// 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.
|
// function properly.
|
||||||
func coinSelect(feeRate SatPerVByte, amt btcutil.Amount,
|
func coinSelect(feeRate SatPerKWeight, amt btcutil.Amount,
|
||||||
coins []*Utxo) ([]*Utxo, btcutil.Amount, error) {
|
coins []*Utxo) ([]*Utxo, btcutil.Amount, error) {
|
||||||
|
|
||||||
amtNeeded := amt
|
amtNeeded := amt
|
||||||
@ -1441,7 +1441,8 @@ func coinSelect(feeRate SatPerVByte, amt btcutil.Amount,
|
|||||||
// amount isn't enough to pay fees, then increase the requested
|
// amount isn't enough to pay fees, then increase the requested
|
||||||
// coin amount by the estimate required fee, performing another
|
// coin amount by the estimate required fee, performing another
|
||||||
// round of coin selection.
|
// round of coin selection.
|
||||||
requiredFee := feeRate.FeeForVSize(int64(weightEstimate.VSize()))
|
totalWeight := int64(weightEstimate.Weight())
|
||||||
|
requiredFee := feeRate.FeeForWeight(totalWeight)
|
||||||
if overShootAmt < requiredFee {
|
if overShootAmt < requiredFee {
|
||||||
amtNeeded = amt + requiredFee
|
amtNeeded = amt + requiredFee
|
||||||
continue
|
continue
|
||||||
|
@ -994,15 +994,15 @@ func (u *utxoNursery) createSweepTx(kgtnOutputs []kidOutput,
|
|||||||
utxnLog.Infof("Creating sweep transaction for %v CSV inputs, %v CLTV "+
|
utxnLog.Infof("Creating sweep transaction for %v CSV inputs, %v CLTV "+
|
||||||
"inputs", len(csvOutputs), len(cltvOutputs))
|
"inputs", len(csvOutputs), len(cltvOutputs))
|
||||||
|
|
||||||
txVSize := int64(weightEstimate.VSize())
|
txWeight := int64(weightEstimate.Weight())
|
||||||
return u.populateSweepTx(txVSize, classHeight, csvOutputs, cltvOutputs)
|
return u.populateSweepTx(txWeight, classHeight, csvOutputs, cltvOutputs)
|
||||||
}
|
}
|
||||||
|
|
||||||
// populateSweepTx populate the final sweeping transaction with all witnesses
|
// populateSweepTx populate the final sweeping transaction with all witnesses
|
||||||
// in place for all inputs using the provided txn fee. The created transaction
|
// 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
|
// has a single output sending all the funds back to the source wallet, after
|
||||||
// accounting for the fee estimate.
|
// accounting for the fee estimate.
|
||||||
func (u *utxoNursery) populateSweepTx(txVSize int64, classHeight uint32,
|
func (u *utxoNursery) populateSweepTx(txWeight int64, classHeight uint32,
|
||||||
csvInputs []CsvSpendableOutput,
|
csvInputs []CsvSpendableOutput,
|
||||||
cltvInputs []SpendableOutput) (*wire.MsgTx, error) {
|
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.
|
// 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 {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
txFee := feePerVSize.FeeForVSize(txVSize)
|
txFee := feePerKw.FeeForWeight(txWeight)
|
||||||
|
|
||||||
// Sweep as much possible, after subtracting txn fees.
|
// Sweep as much possible, after subtracting txn fees.
|
||||||
sweepAmt := int64(totalSum - txFee)
|
sweepAmt := int64(totalSum - txFee)
|
||||||
|
Loading…
Reference in New Issue
Block a user