• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

lightningnetwork / lnd / 13211764208

08 Feb 2025 03:08AM UTC coverage: 49.288% (-9.5%) from 58.815%
13211764208

Pull #9489

github

calvinrzachman
itest: verify switchrpc server enforces send then track

We prevent the rpc server from allowing onion dispatches for
attempt IDs which have already been tracked by rpc clients.

This helps protect the client from leaking a duplicate onion
attempt. NOTE: This is not the only method for solving this
issue! The issue could be addressed via careful client side
programming which accounts for the uncertainty and async
nature of dispatching onions to a remote process via RPC.
This would require some lnd ChannelRouter changes for how
we intend to use these RPCs though.
Pull Request #9489: multi: add BuildOnion, SendOnion, and TrackOnion RPCs

474 of 990 new or added lines in 11 files covered. (47.88%)

27321 existing lines in 435 files now uncovered.

101192 of 205306 relevant lines covered (49.29%)

1.54 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

83.16
/sweep/weight_estimator.go
1
package sweep
2

3
import (
4
        "github.com/btcsuite/btcd/btcutil"
5
        "github.com/btcsuite/btcd/chaincfg/chainhash"
6
        "github.com/btcsuite/btcd/wire"
7
        "github.com/lightningnetwork/lnd/input"
8
        "github.com/lightningnetwork/lnd/lntypes"
9
        "github.com/lightningnetwork/lnd/lnwallet/chainfee"
10
)
11

12
// weightEstimator wraps a standard weight estimator instance and adds to that
13
// support for child-pays-for-parent.
14
type weightEstimator struct {
15
        estimator     input.TxWeightEstimator
16
        feeRate       chainfee.SatPerKWeight
17
        parents       map[chainhash.Hash]struct{}
18
        parentsFee    btcutil.Amount
19
        parentsWeight lntypes.WeightUnit
20

21
        // maxFeeRate is the max allowed fee rate configured by the user.
22
        maxFeeRate chainfee.SatPerKWeight
23
}
24

25
// newWeightEstimator instantiates a new sweeper weight estimator.
26
func newWeightEstimator(
27
        feeRate, maxFeeRate chainfee.SatPerKWeight) *weightEstimator {
3✔
28

3✔
29
        return &weightEstimator{
3✔
30
                feeRate:    feeRate,
3✔
31
                maxFeeRate: maxFeeRate,
3✔
32
                parents:    make(map[chainhash.Hash]struct{}),
3✔
33
        }
3✔
34
}
3✔
35

36
// add adds the weight of the given input to the weight estimate.
37
func (w *weightEstimator) add(inp input.Input) error {
3✔
38
        // If there is a parent tx, add the parent's fee and weight.
3✔
39
        w.tryAddParent(inp)
3✔
40

3✔
41
        wt := inp.WitnessType()
3✔
42

3✔
43
        return wt.AddWeightEstimation(&w.estimator)
3✔
44
}
3✔
45

46
// tryAddParent examines the input and updates parent tx totals if required for
47
// cpfp.
48
func (w *weightEstimator) tryAddParent(inp input.Input) {
3✔
49
        // Get unconfirmed parent info from the input.
3✔
50
        unconfParent := inp.UnconfParent()
3✔
51

3✔
52
        // If there is no parent, there is nothing to add.
3✔
53
        if unconfParent == nil {
6✔
54
                return
3✔
55
        }
3✔
56

57
        // If we've already accounted for the parent tx, don't do it
58
        // again. This can happens when two outputs of the parent tx are
59
        // included in the same sweep tx.
60
        parentHash := inp.OutPoint().Hash
3✔
61
        if _, ok := w.parents[parentHash]; ok {
3✔
62
                return
×
63
        }
×
64

65
        // Calculate parent fee rate.
66
        parentFeeRate := chainfee.SatPerKWeight(unconfParent.Fee) * 1000 /
3✔
67
                chainfee.SatPerKWeight(unconfParent.Weight)
3✔
68

3✔
69
        // Ignore parents that pay at least the fee rate of this transaction.
3✔
70
        // Parent pays for child is not happening.
3✔
71
        if parentFeeRate >= w.feeRate {
6✔
72
                return
3✔
73
        }
3✔
74

75
        // Include parent.
76
        w.parents[parentHash] = struct{}{}
3✔
77
        w.parentsFee += unconfParent.Fee
3✔
78
        w.parentsWeight += unconfParent.Weight
3✔
79
}
80

81
// addP2WKHOutput updates the weight estimate to account for an additional
82
// native P2WKH output.
83
func (w *weightEstimator) addP2WKHOutput() {
3✔
84
        w.estimator.AddP2WKHOutput()
3✔
85
}
3✔
86

87
// addP2TROutput updates the weight estimate to account for an additional native
88
// SegWit v1 P2TR output.
89
func (w *weightEstimator) addP2TROutput() {
3✔
90
        w.estimator.AddP2TROutput()
3✔
91
}
3✔
92

93
// addP2WSHOutput updates the weight estimate to account for an additional
94
// segwit v0 P2WSH output.
95
func (w *weightEstimator) addP2WSHOutput() {
3✔
96
        w.estimator.AddP2WSHOutput()
3✔
97
}
3✔
98

99
// addOutput updates the weight estimate to account for the known
100
// output given.
101
func (w *weightEstimator) addOutput(txOut *wire.TxOut) {
3✔
102
        w.estimator.AddTxOutput(txOut)
3✔
103
}
3✔
104

105
// weight gets the estimated weight of the transaction.
106
func (w *weightEstimator) weight() lntypes.WeightUnit {
3✔
107
        return w.estimator.Weight()
3✔
108
}
3✔
109

110
// fee returns the tx fee to use for the aggregated inputs and outputs, which
111
// is different from feeWithParent as it doesn't take into account unconfirmed
112
// parent transactions.
113
func (w *weightEstimator) fee() btcutil.Amount {
3✔
114
        // Calculate the weight of the transaction.
3✔
115
        weight := w.estimator.Weight()
3✔
116

3✔
117
        // Calculate the fee.
3✔
118
        fee := w.feeRate.FeeForWeight(weight)
3✔
119

3✔
120
        return fee
3✔
121
}
3✔
122

123
// feeWithParent returns the tx fee to use for the aggregated inputs and
124
// outputs, taking into account unconfirmed parent transactions (cpfp).
125
func (w *weightEstimator) feeWithParent() btcutil.Amount {
3✔
126
        // Calculate fee and weight for just this tx.
3✔
127
        childWeight := w.estimator.Weight()
3✔
128

3✔
129
        // Add combined weight of unconfirmed parent txes.
3✔
130
        totalWeight := childWeight + w.parentsWeight
3✔
131

3✔
132
        // Subtract fee already paid by parents.
3✔
133
        fee := w.feeRate.FeeForWeight(totalWeight) - w.parentsFee
3✔
134

3✔
135
        // Clamp the fee to what would be required if no parent txes were paid
3✔
136
        // for. This is to make sure no rounding errors can get us into trouble.
3✔
137
        childFee := w.feeRate.FeeForWeight(childWeight)
3✔
138
        if childFee > fee {
3✔
139
                fee = childFee
×
140
        }
×
141

142
        // Exit early if maxFeeRate is not set.
143
        if w.maxFeeRate == 0 {
3✔
UNCOV
144
                return fee
×
UNCOV
145
        }
×
146

147
        // Clamp the fee to the max fee rate.
148
        maxFee := w.maxFeeRate.FeeForWeight(childWeight)
3✔
149
        if fee > maxFee {
3✔
UNCOV
150
                // Calculate the effective fee rate for logging.
×
UNCOV
151
                childFeeRate := chainfee.SatPerKWeight(
×
UNCOV
152
                        fee * 1000 / btcutil.Amount(childWeight),
×
UNCOV
153
                )
×
UNCOV
154
                log.Warnf("Child fee rate %v exceeds max allowed fee rate %v, "+
×
UNCOV
155
                        "returning fee %v instead of %v", childFeeRate,
×
UNCOV
156
                        w.maxFeeRate, maxFee, fee)
×
UNCOV
157

×
UNCOV
158
                fee = maxFee
×
UNCOV
159
        }
×
160

161
        return fee
3✔
162
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc