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

lightningnetwork / lnd / 14513053602

17 Apr 2025 09:56AM UTC coverage: 56.754% (-12.3%) from 69.035%
14513053602

Pull #9727

github

web-flow
Merge 5fb0f4317 into 24fdae7df
Pull Request #9727: Aux bandwidth manager: also pass HTLC blob to `ShouldHandleTraffic`

3 of 8 new or added lines in 2 files covered. (37.5%)

24357 existing lines in 290 files now uncovered.

107518 of 189445 relevant lines covered (56.75%)

22634.92 hits per line

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

0.0
/lntest/utils.go
1
package lntest
2

3
import (
4
        "fmt"
5
        "io"
6
        "math"
7
        "os"
8
        "strconv"
9
        "strings"
10

11
        "github.com/btcsuite/btcd/btcutil"
12
        "github.com/btcsuite/btcd/wire"
13
        "github.com/lightningnetwork/lnd/input"
14
        "github.com/lightningnetwork/lnd/lnrpc"
15
        "github.com/lightningnetwork/lnd/lntest/wait"
16
        "github.com/lightningnetwork/lnd/lntypes"
17
        "github.com/lightningnetwork/lnd/lnwallet"
18
        "github.com/lightningnetwork/lnd/lnwallet/chainfee"
19
        "github.com/lightningnetwork/lnd/lnwire"
20
)
21

22
const (
23
        // NeutrinoBackendName is the name of the neutrino backend.
24
        NeutrinoBackendName = "neutrino"
25

26
        DefaultTimeout = wait.DefaultTimeout
27

28
        // noFeeLimitMsat is used to specify we will put no requirements on fee
29
        // charged when choosing a route path.
30
        noFeeLimitMsat = math.MaxInt64
31
)
32

33
// CopyFile copies the file src to dest.
34
func CopyFile(dest, src string) error {
×
35
        s, err := os.Open(src)
×
36
        if err != nil {
×
37
                return err
×
38
        }
×
39
        defer s.Close()
×
40

×
41
        d, err := os.Create(dest)
×
42
        if err != nil {
×
43
                return err
×
44
        }
×
45

46
        if _, err := io.Copy(d, s); err != nil {
×
47
                d.Close()
×
48
                return err
×
49
        }
×
50

51
        return d.Close()
×
52
}
53

54
// errNumNotMatched is a helper method to return a nicely formatted error.
55
func errNumNotMatched(name string, subject string,
56
        want, got, total, old int, desc ...any) error {
×
57

×
58
        err := fmt.Errorf("%s: assert %s failed: want %d, got: %d, total: "+
×
59
                "%d, previously had: %d", name, subject, want, got, total, old)
×
60

×
61
        if len(desc) > 0 {
×
62
                err = fmt.Errorf("%w, desc: %v", err, desc)
×
63
        }
×
64

65
        return err
×
66
}
67

68
// parseDerivationPath parses a path in the form of m/x'/y'/z'/a/b into a slice
69
// of [x, y, z, a, b], meaning that the apostrophe is ignored and 2^31 is _not_
70
// added to the numbers.
71
func ParseDerivationPath(path string) ([]uint32, error) {
×
72
        path = strings.TrimSpace(path)
×
73
        if len(path) == 0 {
×
74
                return nil, fmt.Errorf("path cannot be empty")
×
75
        }
×
76
        if !strings.HasPrefix(path, "m/") {
×
77
                return nil, fmt.Errorf("path must start with m/")
×
78
        }
×
79

80
        // Just the root key, no path was provided. This is valid but not useful
81
        // in most cases.
82
        rest := strings.ReplaceAll(path, "m/", "")
×
83
        if rest == "" {
×
84
                return []uint32{}, nil
×
85
        }
×
86

87
        parts := strings.Split(rest, "/")
×
88
        indices := make([]uint32, len(parts))
×
89
        for i := 0; i < len(parts); i++ {
×
90
                part := parts[i]
×
91
                if strings.Contains(parts[i], "'") {
×
92
                        part = strings.TrimRight(parts[i], "'")
×
93
                }
×
94
                parsed, err := strconv.ParseInt(part, 10, 32)
×
95
                if err != nil {
×
96
                        return nil, fmt.Errorf("could not parse part \"%s\": "+
×
97
                                "%v", part, err)
×
98
                }
×
99
                indices[i] = uint32(parsed)
×
100
        }
101

102
        return indices, nil
×
103
}
104

105
// ChanPointFromPendingUpdate constructs a channel point from a lnrpc pending
106
// update.
107
func ChanPointFromPendingUpdate(pu *lnrpc.PendingUpdate) *lnrpc.ChannelPoint {
×
108
        chanPoint := &lnrpc.ChannelPoint{
×
109
                FundingTxid: &lnrpc.ChannelPoint_FundingTxidBytes{
×
110
                        FundingTxidBytes: pu.Txid,
×
111
                },
×
112
                OutputIndex: pu.OutputIndex,
×
113
        }
×
114

×
115
        return chanPoint
×
116
}
×
117

118
// channelPointStr returns the string representation of the channel's
119
// funding transaction.
120
func channelPointStr(chanPoint *lnrpc.ChannelPoint) string {
×
121
        fundingTxID, err := lnrpc.GetChanPointFundingTxid(chanPoint)
×
122
        if err != nil {
×
123
                return ""
×
124
        }
×
125
        cp := wire.OutPoint{
×
126
                Hash:  *fundingTxID,
×
127
                Index: chanPoint.OutputIndex,
×
128
        }
×
129

×
130
        return cp.String()
×
131
}
132

133
// CommitTypeHasTaproot returns whether commitType is a taproot commitment.
134
func CommitTypeHasTaproot(commitType lnrpc.CommitmentType) bool {
×
135
        switch commitType {
×
136
        case lnrpc.CommitmentType_SIMPLE_TAPROOT:
×
137
                return true
×
138
        default:
×
139
                return false
×
140
        }
141
}
142

143
// CommitTypeHasAnchors returns whether commitType uses anchor outputs.
144
func CommitTypeHasAnchors(commitType lnrpc.CommitmentType) bool {
×
145
        switch commitType {
×
146
        case lnrpc.CommitmentType_ANCHORS,
147
                lnrpc.CommitmentType_SIMPLE_TAPROOT,
148
                lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE:
×
149
                return true
×
150
        default:
×
151
                return false
×
152
        }
153
}
154

155
// NodeArgsForCommitType returns the command line flag to supply to enable this
156
// commitment type.
157
func NodeArgsForCommitType(commitType lnrpc.CommitmentType) []string {
×
158
        switch commitType {
×
159
        case lnrpc.CommitmentType_LEGACY:
×
160
                return []string{"--protocol.legacy.committweak"}
×
161
        case lnrpc.CommitmentType_STATIC_REMOTE_KEY:
×
162
                return []string{}
×
163
        case lnrpc.CommitmentType_ANCHORS:
×
164
                return []string{"--protocol.anchors"}
×
165
        case lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE:
×
166
                return []string{
×
167
                        "--protocol.anchors",
×
168
                        "--protocol.script-enforced-lease",
×
169
                }
×
170
        case lnrpc.CommitmentType_SIMPLE_TAPROOT:
×
171
                return []string{
×
172
                        "--protocol.anchors",
×
173
                        "--protocol.simple-taproot-chans",
×
174
                }
×
175
        }
176

177
        return nil
×
178
}
179

180
// CalcStaticFee calculates appropriate fees for commitment transactions. This
181
// function provides a simple way to allow test balance assertions to take fee
182
// calculations into account.
183
func CalcStaticFee(c lnrpc.CommitmentType, numHTLCs int) btcutil.Amount {
×
184
        //nolint:ll
×
185
        const (
×
186
                htlcWeight         = input.HTLCWeight
×
187
                anchorSize         = 330 * 2
×
188
                defaultSatPerVByte = lnwallet.DefaultAnchorsCommitMaxFeeRateSatPerVByte
×
189
                scale              = 1000
×
190
        )
×
191

×
192
        var (
×
193
                anchors      = btcutil.Amount(0)
×
194
                commitWeight = input.CommitWeight
×
195
                feePerKw     = chainfee.SatPerKWeight(DefaultFeeRateSatPerKw)
×
196
        )
×
197

×
198
        switch {
×
199
        // The taproot commitment type has the extra anchor outputs, but also a
200
        // smaller witness field (will just be a normal key spend), so we need
201
        // to account for that here as well.
202
        case CommitTypeHasTaproot(c):
×
203
                feePerKw = chainfee.SatPerKVByte(
×
204
                        defaultSatPerVByte * scale,
×
205
                ).FeePerKWeight()
×
206

×
207
                commitWeight = input.TaprootCommitWeight
×
208
                anchors = anchorSize
×
209

210
        // The anchor commitment type is slightly heavier, and we must also add
211
        // the value of the two anchors to the resulting fee the initiator
212
        // pays. In addition the fee rate is capped at 10 sat/vbyte for anchor
213
        // channels.
214
        case CommitTypeHasAnchors(c):
×
215
                feePerKw = chainfee.SatPerKVByte(
×
216
                        defaultSatPerVByte * scale,
×
217
                ).FeePerKWeight()
×
218
                commitWeight = input.AnchorCommitWeight
×
219
                anchors = anchorSize
×
220
        }
221

222
        totalWeight := commitWeight + htlcWeight*numHTLCs
×
223

×
224
        return feePerKw.FeeForWeight(lntypes.WeightUnit(totalWeight)) + anchors
×
225
}
226

227
// CalculateMaxHtlc re-implements the RequiredRemoteChannelReserve of the
228
// funding manager's config, which corresponds to the maximum MaxHTLC value we
229
// allow users to set when updating a channel policy.
230
func CalculateMaxHtlc(chanCap btcutil.Amount) uint64 {
×
231
        const ratio = 100
×
232
        reserve := lnwire.NewMSatFromSatoshis(chanCap / ratio)
×
233
        max := lnwire.NewMSatFromSatoshis(chanCap) - reserve
×
234

×
235
        return uint64(max)
×
236
}
×
237

238
// CalcStaticFeeBuffer calculates appropriate fee buffer which must be taken
239
// into account when sending htlcs.
240
func CalcStaticFeeBuffer(c lnrpc.CommitmentType, numHTLCs int) btcutil.Amount {
×
241
        //nolint:ll
×
242
        const (
×
243
                htlcWeight         = input.HTLCWeight
×
244
                defaultSatPerVByte = lnwallet.DefaultAnchorsCommitMaxFeeRateSatPerVByte
×
245
                scale              = 1000
×
246
        )
×
247

×
248
        var (
×
249
                commitWeight = input.CommitWeight
×
250
                feePerKw     = chainfee.SatPerKWeight(DefaultFeeRateSatPerKw)
×
251
        )
×
252

×
253
        switch {
×
254
        // The taproot commitment type has the extra anchor outputs, but also a
255
        // smaller witness field (will just be a normal key spend), so we need
256
        // to account for that here as well.
257
        case CommitTypeHasTaproot(c):
×
258
                feePerKw = chainfee.SatPerKVByte(
×
259
                        defaultSatPerVByte * scale,
×
260
                ).FeePerKWeight()
×
261

×
262
                commitWeight = input.TaprootCommitWeight
×
263

264
        // The anchor commitment type is slightly heavier, and we must also add
265
        // the value of the two anchors to the resulting fee the initiator
266
        // pays. In addition the fee rate is capped at 10 sat/vbyte for anchor
267
        // channels.
268
        case CommitTypeHasAnchors(c):
×
269
                feePerKw = chainfee.SatPerKVByte(
×
270
                        defaultSatPerVByte * scale,
×
271
                ).FeePerKWeight()
×
272
                commitWeight = input.AnchorCommitWeight
×
273
        }
274

275
        // Account for the HTLC which will be required when sending an htlc.
276
        numHTLCs++
×
277

×
278
        totalWeight := commitWeight + numHTLCs*htlcWeight
×
279
        feeBuffer := lnwallet.CalcFeeBuffer(
×
280
                feePerKw, lntypes.WeightUnit(totalWeight),
×
281
        )
×
282

×
283
        return feeBuffer.ToSatoshis()
×
284
}
285

286
// CustomRecordsWithUnendorsed copies the map of custom records and adds an
287
// endorsed signal (replacing in the case of conflict) for assertion in tests.
288
func CustomRecordsWithUnendorsed(
289
        originalRecords lnwire.CustomRecords) map[uint64][]byte {
×
290

×
291
        return originalRecords.MergedCopy(map[uint64][]byte{
×
292
                uint64(lnwire.ExperimentalEndorsementType): {
×
293
                        lnwire.ExperimentalUnendorsed,
×
294
                }},
×
295
        )
×
296
}
×
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