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 }