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

lightningnetwork / lnd / 13980275562

20 Mar 2025 10:06PM UTC coverage: 58.6% (-10.2%) from 68.789%
13980275562

Pull #9623

github

web-flow
Merge b9b960345 into 09b674508
Pull Request #9623: Size msg test msg

0 of 1518 new or added lines in 42 files covered. (0.0%)

26603 existing lines in 443 files now uncovered.

96807 of 165200 relevant lines covered (58.6%)

1.82 hits per line

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

47.06
/lnwire/reply_channel_range.go
1
package lnwire
2

3
import (
4
        "bytes"
5
        "fmt"
6
        "io"
7
        "math"
8
        "sort"
9

10
        "github.com/btcsuite/btcd/chaincfg/chainhash"
11
        "github.com/lightningnetwork/lnd/fn/v2"
12
        "github.com/lightningnetwork/lnd/tlv"
13
        "pgregory.net/rapid"
14
)
15

16
// ReplyChannelRange is the response to the QueryChannelRange message. It
17
// includes the original query, and the next streaming chunk of encoded short
18
// channel ID's as the response. We'll also include a byte that indicates if
19
// this is the last query in the message.
20
type ReplyChannelRange struct {
21
        // ChainHash denotes the target chain that we're trying to synchronize
22
        // channel graph state for.
23
        ChainHash chainhash.Hash
24

25
        // FirstBlockHeight is the first block in the query range. The
26
        // responder should send all new short channel IDs from this block
27
        // until this block plus the specified number of blocks.
28
        FirstBlockHeight uint32
29

30
        // NumBlocks is the number of blocks beyond the first block that short
31
        // channel ID's should be sent for.
32
        NumBlocks uint32
33

34
        // Complete denotes if this is the conclusion of the set of streaming
35
        // responses to the original query.
36
        Complete uint8
37

38
        // EncodingType is a signal to the receiver of the message that
39
        // indicates exactly how the set of short channel ID's that follow have
40
        // been encoded.
41
        EncodingType QueryEncoding
42

43
        // ShortChanIDs is a slice of decoded short channel ID's.
44
        ShortChanIDs []ShortChannelID
45

46
        // Timestamps is an optional set of timestamps corresponding to the
47
        // latest timestamps for the channel update messages corresponding to
48
        // those referenced in the ShortChanIDs list. If this field is used,
49
        // then the length must match the length of ShortChanIDs.
50
        Timestamps Timestamps
51

52
        // ExtraData is the set of data that was appended to this message to
53
        // fill out the full maximum transport message size. These fields can
54
        // be used to specify optional data such as custom TLV fields.
55
        ExtraData ExtraOpaqueData
56

57
        // noSort indicates whether or not to sort the short channel ids before
58
        // writing them out.
59
        //
60
        // NOTE: This should only be used for testing.
61
        noSort bool
62
}
63

64
// NewReplyChannelRange creates a new empty ReplyChannelRange message.
UNCOV
65
func NewReplyChannelRange() *ReplyChannelRange {
×
UNCOV
66
        return &ReplyChannelRange{
×
UNCOV
67
                ExtraData: make([]byte, 0),
×
UNCOV
68
        }
×
UNCOV
69
}
×
70

71
// A compile time check to ensure ReplyChannelRange implements the
72
// lnwire.Message interface.
73
var _ Message = (*ReplyChannelRange)(nil)
74

75
// A compile time check to ensure ReplyChannelRange implements the lnwire.SizeableMessage interface.
76
var _ SizeableMessage = (*ReplyChannelRange)(nil)
77

78
// A compile time check to ensure ReplyChannelRange implements the lnwire.TestMessage
79
// interface.
80
var _ TestMessage = (*ReplyChannelRange)(nil)
81

82
// Decode deserializes a serialized ReplyChannelRange message stored in the
83
// passed io.Reader observing the specified protocol version.
84
//
85
// This is part of the lnwire.Message interface.
86
func (c *ReplyChannelRange) Decode(r io.Reader, pver uint32) error {
3✔
87
        err := ReadElements(r,
3✔
88
                c.ChainHash[:],
3✔
89
                &c.FirstBlockHeight,
3✔
90
                &c.NumBlocks,
3✔
91
                &c.Complete,
3✔
92
        )
3✔
93
        if err != nil {
3✔
UNCOV
94
                return err
×
UNCOV
95
        }
×
96

97
        c.EncodingType, c.ShortChanIDs, err = decodeShortChanIDs(r)
3✔
98
        if err != nil {
3✔
UNCOV
99
                return err
×
UNCOV
100
        }
×
101

102
        var tlvRecords ExtraOpaqueData
3✔
103
        if err := ReadElements(r, &tlvRecords); err != nil {
3✔
UNCOV
104
                return err
×
105
        }
×
106

107
        var timeStamps Timestamps
3✔
108
        typeMap, err := tlvRecords.ExtractRecords(&timeStamps)
3✔
109
        if err != nil {
3✔
UNCOV
110
                return err
×
UNCOV
111
        }
×
112

113
        // Set the corresponding TLV types if they were included in the stream.
114
        if val, ok := typeMap[TimestampsRecordType]; ok && val == nil {
6✔
115
                c.Timestamps = timeStamps
3✔
116

3✔
117
                // Check that a timestamp was provided for each SCID.
3✔
118
                if len(c.Timestamps) != len(c.ShortChanIDs) {
3✔
UNCOV
119
                        return fmt.Errorf("number of timestamps does not " +
×
UNCOV
120
                                "match number of SCIDs")
×
UNCOV
121
                }
×
122
        }
123

124
        if len(tlvRecords) != 0 {
6✔
125
                c.ExtraData = tlvRecords
3✔
126
        }
3✔
127

128
        return nil
3✔
129
}
130

131
// Encode serializes the target ReplyChannelRange into the passed io.Writer
132
// observing the protocol version specified.
133
//
134
// This is part of the lnwire.Message interface.
135
func (c *ReplyChannelRange) Encode(w *bytes.Buffer, pver uint32) error {
3✔
136
        if err := WriteBytes(w, c.ChainHash[:]); err != nil {
3✔
UNCOV
137
                return err
×
138
        }
×
139

140
        if err := WriteUint32(w, c.FirstBlockHeight); err != nil {
3✔
UNCOV
141
                return err
×
142
        }
×
143

144
        if err := WriteUint32(w, c.NumBlocks); err != nil {
3✔
UNCOV
145
                return err
×
146
        }
×
147

148
        if err := WriteUint8(w, c.Complete); err != nil {
3✔
UNCOV
149
                return err
×
150
        }
×
151

152
        // For both of the current encoding types, the channel ID's are to be
153
        // sorted in place, so we'll do that now. The sorting is applied unless
154
        // we were specifically requested not to for testing purposes.
155
        if !c.noSort {
6✔
156
                var scidPreSortIndex map[uint64]int
3✔
157
                if len(c.Timestamps) != 0 {
6✔
158
                        // Sanity check that a timestamp was provided for each
3✔
159
                        // SCID.
3✔
160
                        if len(c.Timestamps) != len(c.ShortChanIDs) {
3✔
UNCOV
161
                                return fmt.Errorf("must provide a timestamp " +
×
UNCOV
162
                                        "pair for each of the given SCIDs")
×
UNCOV
163
                        }
×
164

165
                        // Create a map from SCID value to the original index of
166
                        // the SCID in the unsorted list.
167
                        scidPreSortIndex = make(
3✔
168
                                map[uint64]int, len(c.ShortChanIDs),
3✔
169
                        )
3✔
170
                        for i, scid := range c.ShortChanIDs {
6✔
171
                                scidPreSortIndex[scid.ToUint64()] = i
3✔
172
                        }
3✔
173

174
                        // Sanity check that there were no duplicates in the
175
                        // SCID list.
176
                        if len(scidPreSortIndex) != len(c.ShortChanIDs) {
3✔
UNCOV
177
                                return fmt.Errorf("scid list should not " +
×
UNCOV
178
                                        "contain duplicates")
×
UNCOV
179
                        }
×
180
                }
181

182
                // Now sort the SCIDs.
183
                sort.Slice(c.ShortChanIDs, func(i, j int) bool {
6✔
184
                        return c.ShortChanIDs[i].ToUint64() <
3✔
185
                                c.ShortChanIDs[j].ToUint64()
3✔
186
                })
3✔
187

188
                if len(c.Timestamps) != 0 {
6✔
189
                        timestamps := make(Timestamps, len(c.Timestamps))
3✔
190

3✔
191
                        for i, scid := range c.ShortChanIDs {
6✔
192
                                timestamps[i] = []ChanUpdateTimestamps(
3✔
193
                                        c.Timestamps,
3✔
194
                                )[scidPreSortIndex[scid.ToUint64()]]
3✔
195
                        }
3✔
196
                        c.Timestamps = timestamps
3✔
197
                }
198
        }
199

200
        err := encodeShortChanIDs(w, c.EncodingType, c.ShortChanIDs)
3✔
201
        if err != nil {
3✔
UNCOV
202
                return err
×
203
        }
×
204

205
        recordProducers := make([]tlv.RecordProducer, 0, 1)
3✔
206
        if len(c.Timestamps) != 0 {
6✔
207
                recordProducers = append(recordProducers, &c.Timestamps)
3✔
208
        }
3✔
209
        err = EncodeMessageExtraData(&c.ExtraData, recordProducers...)
3✔
210
        if err != nil {
3✔
UNCOV
211
                return err
×
212
        }
×
213

214
        return WriteBytes(w, c.ExtraData)
3✔
215
}
216

217
// MsgType returns the integer uniquely identifying this message type on the
218
// wire.
219
//
220
// This is part of the lnwire.Message interface.
221
func (c *ReplyChannelRange) MsgType() MessageType {
3✔
222
        return MsgReplyChannelRange
3✔
223
}
3✔
224

225
// LastBlockHeight returns the last block height covered by the range of a
226
// QueryChannelRange message.
227
func (c *ReplyChannelRange) LastBlockHeight() uint32 {
3✔
228
        // Handle overflows by casting to uint64.
3✔
229
        lastBlockHeight := uint64(c.FirstBlockHeight) + uint64(c.NumBlocks) - 1
3✔
230
        if lastBlockHeight > math.MaxUint32 {
3✔
UNCOV
231
                return math.MaxUint32
×
232
        }
×
233
        return uint32(lastBlockHeight)
3✔
234
}
235

236
// SerializedSize returns the serialized size of the message in bytes.
237
//
238
// This is part of the lnwire.SizeableMessage interface.
NEW
239
func (c *ReplyChannelRange) SerializedSize() (uint32, error) {
×
NEW
240
        return MessageSerializedSize(c)
×
NEW
241
}
×
242

243
// RandTestMessage populates the message with random data suitable for testing.
244
// It uses the rapid testing framework to generate random values.
245
//
246
// This is part of the TestMessage interface.
NEW
247
func (c *ReplyChannelRange) RandTestMessage(t *rapid.T) Message {
×
NEW
248
        msg := &ReplyChannelRange{
×
NEW
249
                FirstBlockHeight: uint32(rapid.IntRange(0, 1000000).Draw(
×
NEW
250
                        t, "firstBlockHeight"),
×
NEW
251
                ),
×
NEW
252
                NumBlocks: uint32(rapid.IntRange(1, 10000).Draw(
×
NEW
253
                        t, "numBlocks"),
×
NEW
254
                ),
×
NEW
255
                Complete: uint8(rapid.IntRange(0, 1).Draw(t, "complete")),
×
NEW
256
                EncodingType: QueryEncoding(
×
NEW
257
                        rapid.IntRange(0, 1).Draw(t, "encodingType"),
×
NEW
258
                ),
×
NEW
259
                ExtraData: RandExtraOpaqueData(t, nil),
×
NEW
260
        }
×
NEW
261

×
NEW
262
        msg.ChainHash = RandChainHash(t)
×
NEW
263

×
NEW
264
        numShortChanIDs := rapid.IntRange(0, 20).Draw(t, "numShortChanIDs")
×
NEW
265
        if numShortChanIDs == 0 {
×
NEW
266
                return msg
×
NEW
267
        }
×
268

NEW
269
        scidSet := fn.NewSet[ShortChannelID]()
×
NEW
270
        scids := make([]ShortChannelID, numShortChanIDs)
×
NEW
271
        for i := 0; i < numShortChanIDs; i++ {
×
NEW
272
                scid := RandShortChannelID(t)
×
NEW
273
                for scidSet.Contains(scid) {
×
NEW
274
                        scid = RandShortChannelID(t)
×
NEW
275
                }
×
276

NEW
277
                scids[i] = scid
×
NEW
278

×
NEW
279
                scidSet.Add(scid)
×
280
        }
281

282
        // Make sure there're no duplicates.
NEW
283
        msg.ShortChanIDs = scids
×
NEW
284

×
NEW
285
        if rapid.Bool().Draw(t, "includeTimestamps") && numShortChanIDs > 0 {
×
NEW
286
                msg.Timestamps = make(Timestamps, numShortChanIDs)
×
NEW
287
                for i := 0; i < numShortChanIDs; i++ {
×
NEW
288
                        msg.Timestamps[i] = ChanUpdateTimestamps{
×
NEW
289
                                Timestamp1: uint32(rapid.IntRange(0, math.MaxUint32).Draw(t, fmt.Sprintf("timestamp-1-%d", i))), //nolint:ll
×
NEW
290
                                Timestamp2: uint32(rapid.IntRange(0, math.MaxUint32).Draw(t, fmt.Sprintf("timestamp-2-%d", i))), //nolint:ll
×
NEW
291
                        }
×
NEW
292
                }
×
293
        }
294

NEW
295
        return msg
×
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