github.com/decred/dcrlnd@v0.7.6/sweep/weight_estimator.go (about)

     1  package sweep
     2  
     3  import (
     4  	"github.com/decred/dcrd/chaincfg/chainhash"
     5  	"github.com/decred/dcrd/dcrutil/v4"
     6  	"github.com/decred/dcrd/wire"
     7  	"github.com/decred/dcrlnd/input"
     8  	"github.com/decred/dcrlnd/lnwallet/chainfee"
     9  )
    10  
    11  // sizeEstimator wraps a standard weight estimator instance.
    12  type sizeEstimator struct {
    13  	estimator   input.TxSizeEstimator
    14  	feeRate     chainfee.AtomPerKByte
    15  	parents     map[chainhash.Hash]struct{}
    16  	parentsFee  dcrutil.Amount
    17  	parentsSize int64
    18  }
    19  
    20  // newSizeEstimator instantiates a new sweeper size estimator.
    21  func newSizeEstimator(feeRate chainfee.AtomPerKByte) *sizeEstimator {
    22  	return &sizeEstimator{
    23  		feeRate: feeRate,
    24  		parents: make(map[chainhash.Hash]struct{}),
    25  	}
    26  }
    27  
    28  // add adds the size of the given input to the size estimate.
    29  func (w *sizeEstimator) add(inp input.Input) error {
    30  	// If there is a parent tx, add the parent's fee and size.
    31  	w.tryAddParent(inp)
    32  
    33  	wt := inp.WitnessType()
    34  
    35  	return wt.AddSizeEstimation(&w.estimator)
    36  }
    37  
    38  // tryAddParent examines the input and updates parent tx totals if required for
    39  // cpfp.
    40  func (w *sizeEstimator) tryAddParent(inp input.Input) {
    41  	// Get unconfirmed parent info from the input.
    42  	unconfParent := inp.UnconfParent()
    43  
    44  	// If there is no parent, there is nothing to add.
    45  	if unconfParent == nil {
    46  		return
    47  	}
    48  
    49  	// If we've already accounted for the parent tx, don't do it
    50  	// again. This can happens when two outputs of the parent tx are
    51  	// included in the same sweep tx.
    52  	parentHash := inp.OutPoint().Hash
    53  	if _, ok := w.parents[parentHash]; ok {
    54  		return
    55  	}
    56  
    57  	// Calculate parent fee rate.
    58  	parentFeeRate := chainfee.AtomPerKByte(unconfParent.Fee) * 1000 /
    59  		chainfee.AtomPerKByte(unconfParent.Size)
    60  
    61  	// Ignore parents that pay at least the fee rate of this transaction.
    62  	// Parent pays for child is not happening.
    63  	if parentFeeRate >= w.feeRate {
    64  		return
    65  	}
    66  
    67  	// Include parent.
    68  	w.parents[parentHash] = struct{}{}
    69  	w.parentsFee += unconfParent.Fee
    70  	w.parentsSize += unconfParent.Size
    71  }
    72  
    73  // addP2PKHOutput updates the size estimate to account for an additional
    74  // native P2PKH output.
    75  func (w *sizeEstimator) addP2PKHOutput() {
    76  	w.estimator.AddP2PKHOutput()
    77  }
    78  
    79  // addOutput updates the weight estimate to account for the known
    80  // output given.
    81  func (w *sizeEstimator) addOutput(txOut *wire.TxOut) {
    82  	w.estimator.AddTxOutput(txOut)
    83  }
    84  
    85  // size gets the estimated size of the transaction.
    86  func (w *sizeEstimator) size() int {
    87  	return int(w.estimator.Size())
    88  }
    89  
    90  // fee returns the tx fee to use for the aggregated inputs and outputs, taking
    91  // into account unconfirmed parent transactions (cpfp).
    92  func (w *sizeEstimator) fee() dcrutil.Amount {
    93  	// Calculate fee and size for just this tx.
    94  	childSize := w.estimator.Size()
    95  
    96  	// Add combined weight of unconfirmed parent txes.
    97  	totalSize := childSize + w.parentsSize
    98  
    99  	// Subtract fee already paid by parents.
   100  	fee := w.feeRate.FeeForSize(totalSize) - w.parentsFee
   101  
   102  	// Clamp the fee to what would be required if no parent txes were paid
   103  	// for. This is to make sure no rounding errors can get us into trouble.
   104  	childFee := w.feeRate.FeeForSize(childSize)
   105  	if childFee > fee {
   106  		fee = childFee
   107  	}
   108  
   109  	return fee
   110  }