• 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

66.67
/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/tlv"
12
)
13

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

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

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

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

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

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

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

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

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

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

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

73
// Decode deserializes a serialized ReplyChannelRange message stored in the
74
// passed io.Reader observing the specified protocol version.
75
//
76
// This is part of the lnwire.Message interface.
77
func (c *ReplyChannelRange) Decode(r io.Reader, pver uint32) error {
3✔
78
        err := ReadElements(r,
3✔
79
                c.ChainHash[:],
3✔
80
                &c.FirstBlockHeight,
3✔
81
                &c.NumBlocks,
3✔
82
                &c.Complete,
3✔
83
        )
3✔
84
        if err != nil {
3✔
UNCOV
85
                return err
×
UNCOV
86
        }
×
87

88
        c.EncodingType, c.ShortChanIDs, err = decodeShortChanIDs(r)
3✔
89
        if err != nil {
3✔
UNCOV
90
                return err
×
UNCOV
91
        }
×
92

93
        var tlvRecords ExtraOpaqueData
3✔
94
        if err := ReadElements(r, &tlvRecords); err != nil {
3✔
95
                return err
×
96
        }
×
97

98
        var timeStamps Timestamps
3✔
99
        typeMap, err := tlvRecords.ExtractRecords(&timeStamps)
3✔
100
        if err != nil {
3✔
UNCOV
101
                return err
×
UNCOV
102
        }
×
103

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

3✔
108
                // Check that a timestamp was provided for each SCID.
3✔
109
                if len(c.Timestamps) != len(c.ShortChanIDs) {
3✔
UNCOV
110
                        return fmt.Errorf("number of timestamps does not " +
×
UNCOV
111
                                "match number of SCIDs")
×
UNCOV
112
                }
×
113
        }
114

115
        if len(tlvRecords) != 0 {
6✔
116
                c.ExtraData = tlvRecords
3✔
117
        }
3✔
118

119
        return nil
3✔
120
}
121

122
// Encode serializes the target ReplyChannelRange into the passed io.Writer
123
// observing the protocol version specified.
124
//
125
// This is part of the lnwire.Message interface.
126
func (c *ReplyChannelRange) Encode(w *bytes.Buffer, pver uint32) error {
3✔
127
        if err := WriteBytes(w, c.ChainHash[:]); err != nil {
3✔
128
                return err
×
129
        }
×
130

131
        if err := WriteUint32(w, c.FirstBlockHeight); err != nil {
3✔
132
                return err
×
133
        }
×
134

135
        if err := WriteUint32(w, c.NumBlocks); err != nil {
3✔
136
                return err
×
137
        }
×
138

139
        if err := WriteUint8(w, c.Complete); err != nil {
3✔
140
                return err
×
141
        }
×
142

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

156
                        // Create a map from SCID value to the original index of
157
                        // the SCID in the unsorted list.
158
                        scidPreSortIndex = make(
3✔
159
                                map[uint64]int, len(c.ShortChanIDs),
3✔
160
                        )
3✔
161
                        for i, scid := range c.ShortChanIDs {
6✔
162
                                scidPreSortIndex[scid.ToUint64()] = i
3✔
163
                        }
3✔
164

165
                        // Sanity check that there were no duplicates in the
166
                        // SCID list.
167
                        if len(scidPreSortIndex) != len(c.ShortChanIDs) {
3✔
UNCOV
168
                                return fmt.Errorf("scid list should not " +
×
UNCOV
169
                                        "contain duplicates")
×
UNCOV
170
                        }
×
171
                }
172

173
                // Now sort the SCIDs.
174
                sort.Slice(c.ShortChanIDs, func(i, j int) bool {
6✔
175
                        return c.ShortChanIDs[i].ToUint64() <
3✔
176
                                c.ShortChanIDs[j].ToUint64()
3✔
177
                })
3✔
178

179
                if len(c.Timestamps) != 0 {
6✔
180
                        timestamps := make(Timestamps, len(c.Timestamps))
3✔
181

3✔
182
                        for i, scid := range c.ShortChanIDs {
6✔
183
                                timestamps[i] = []ChanUpdateTimestamps(
3✔
184
                                        c.Timestamps,
3✔
185
                                )[scidPreSortIndex[scid.ToUint64()]]
3✔
186
                        }
3✔
187
                        c.Timestamps = timestamps
3✔
188
                }
189
        }
190

191
        err := encodeShortChanIDs(w, c.EncodingType, c.ShortChanIDs)
3✔
192
        if err != nil {
3✔
193
                return err
×
194
        }
×
195

196
        recordProducers := make([]tlv.RecordProducer, 0, 1)
3✔
197
        if len(c.Timestamps) != 0 {
6✔
198
                recordProducers = append(recordProducers, &c.Timestamps)
3✔
199
        }
3✔
200
        err = EncodeMessageExtraData(&c.ExtraData, recordProducers...)
3✔
201
        if err != nil {
3✔
202
                return err
×
203
        }
×
204

205
        return WriteBytes(w, c.ExtraData)
3✔
206
}
207

208
// MsgType returns the integer uniquely identifying this message type on the
209
// wire.
210
//
211
// This is part of the lnwire.Message interface.
212
func (c *ReplyChannelRange) MsgType() MessageType {
3✔
213
        return MsgReplyChannelRange
3✔
214
}
3✔
215

216
// LastBlockHeight returns the last block height covered by the range of a
217
// QueryChannelRange message.
218
func (c *ReplyChannelRange) LastBlockHeight() uint32 {
3✔
219
        // Handle overflows by casting to uint64.
3✔
220
        lastBlockHeight := uint64(c.FirstBlockHeight) + uint64(c.NumBlocks) - 1
3✔
221
        if lastBlockHeight > math.MaxUint32 {
3✔
222
                return math.MaxUint32
×
223
        }
×
224
        return uint32(lastBlockHeight)
3✔
225
}
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