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

lightningnetwork / lnd / 13980885714

20 Mar 2025 10:53PM UTC coverage: 58.613% (-10.2%) from 68.789%
13980885714

Pull #9623

github

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

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

27755 existing lines in 442 files now uncovered.

96886 of 165299 relevant lines covered (58.61%)

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
76
// lnwire.SizeableMessage interface.
77
var _ SizeableMessage = (*ReplyChannelRange)(nil)
78

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

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

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

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

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

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

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

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

129
        return nil
3✔
130
}
131

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

NEW
278
                scids[i] = scid
×
NEW
279

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

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

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

NEW
296
        return msg
×
297
}
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