• 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

68.38
/lnwire/message.go
1
// Copyright (c) 2013-2017 The btcsuite developers
2
// Copyright (c) 2015-2016 The Decred developers
3
// code derived from https://github .com/btcsuite/btcd/blob/master/wire/message.go
4
// Copyright (C) 2015-2022 The Lightning Network Developers
5

6
package lnwire
7

8
import (
9
        "bytes"
10
        "encoding/binary"
11
        "fmt"
12
        "io"
13
)
14

15
// MessageType is the unique 2 byte big-endian integer that indicates the type
16
// of message on the wire. All messages have a very simple header which
17
// consists simply of 2-byte message type. We omit a length field, and checksum
18
// as the Lightning Protocol is intended to be encapsulated within a
19
// confidential+authenticated cryptographic messaging protocol.
20
type MessageType uint16
21

22
// The currently defined message types within this current version of the
23
// Lightning protocol.
24
const (
25
        MsgWarning                 MessageType = 1
26
        MsgStfu                                = 2
27
        MsgInit                                = 16
28
        MsgError                               = 17
29
        MsgPing                                = 18
30
        MsgPong                                = 19
31
        MsgOpenChannel                         = 32
32
        MsgAcceptChannel                       = 33
33
        MsgFundingCreated                      = 34
34
        MsgFundingSigned                       = 35
35
        MsgChannelReady                        = 36
36
        MsgShutdown                            = 38
37
        MsgClosingSigned                       = 39
38
        MsgClosingComplete                     = 40
39
        MsgClosingSig                          = 41
40
        MsgDynPropose                          = 111
41
        MsgDynAck                              = 113
42
        MsgDynReject                           = 115
43
        MsgUpdateAddHTLC                       = 128
44
        MsgUpdateFulfillHTLC                   = 130
45
        MsgUpdateFailHTLC                      = 131
46
        MsgCommitSig                           = 132
47
        MsgRevokeAndAck                        = 133
48
        MsgUpdateFee                           = 134
49
        MsgUpdateFailMalformedHTLC             = 135
50
        MsgChannelReestablish                  = 136
51
        MsgChannelAnnouncement                 = 256
52
        MsgNodeAnnouncement                    = 257
53
        MsgChannelUpdate                       = 258
54
        MsgAnnounceSignatures                  = 259
55
        MsgAnnounceSignatures2                 = 260
56
        MsgQueryShortChanIDs                   = 261
57
        MsgReplyShortChanIDsEnd                = 262
58
        MsgQueryChannelRange                   = 263
59
        MsgReplyChannelRange                   = 264
60
        MsgGossipTimestampRange                = 265
61
        MsgChannelAnnouncement2                = 267
62
        MsgChannelUpdate2                      = 271
63
        MsgKickoffSig                          = 777
64
)
65

66
// IsChannelUpdate is a filter function that discerns channel update messages
67
// from the other messages in the Lightning Network Protocol.
68
func (t MessageType) IsChannelUpdate() bool {
3✔
69
        switch t {
3✔
70
        case MsgUpdateAddHTLC:
3✔
71
                return true
3✔
72
        case MsgUpdateFulfillHTLC:
3✔
73
                return true
3✔
74
        case MsgUpdateFailHTLC:
3✔
75
                return true
3✔
76
        case MsgUpdateFailMalformedHTLC:
3✔
77
                return true
3✔
UNCOV
78
        case MsgUpdateFee:
×
UNCOV
79
                return true
×
80
        default:
3✔
81
                return false
3✔
82
        }
83
}
84

85
// ErrorEncodeMessage is used when failed to encode the message payload.
UNCOV
86
func ErrorEncodeMessage(err error) error {
×
UNCOV
87
        return fmt.Errorf("failed to encode message to buffer, got %w", err)
×
UNCOV
88
}
×
89

90
// ErrorWriteMessageType is used when failed to write the message type.
91
func ErrorWriteMessageType(err error) error {
×
92
        return fmt.Errorf("failed to write message type, got %w", err)
×
93
}
×
94

95
// ErrorPayloadTooLarge is used when the payload size exceeds the
96
// MaxMsgBody.
UNCOV
97
func ErrorPayloadTooLarge(size int) error {
×
UNCOV
98
        return fmt.Errorf(
×
UNCOV
99
                "message payload is too large - encoded %d bytes, "+
×
UNCOV
100
                        "but maximum message payload is %d bytes",
×
UNCOV
101
                size, MaxMsgBody,
×
UNCOV
102
        )
×
UNCOV
103
}
×
104

105
// String return the string representation of message type.
106
func (t MessageType) String() string {
3✔
107
        switch t {
3✔
UNCOV
108
        case MsgWarning:
×
UNCOV
109
                return "Warning"
×
110
        case MsgStfu:
3✔
111
                return "Stfu"
3✔
112
        case MsgInit:
3✔
113
                return "Init"
3✔
114
        case MsgOpenChannel:
3✔
115
                return "MsgOpenChannel"
3✔
116
        case MsgAcceptChannel:
3✔
117
                return "MsgAcceptChannel"
3✔
118
        case MsgFundingCreated:
3✔
119
                return "MsgFundingCreated"
3✔
120
        case MsgFundingSigned:
3✔
121
                return "MsgFundingSigned"
3✔
122
        case MsgChannelReady:
3✔
123
                return "ChannelReady"
3✔
124
        case MsgShutdown:
3✔
125
                return "Shutdown"
3✔
126
        case MsgClosingSigned:
3✔
127
                return "ClosingSigned"
3✔
UNCOV
128
        case MsgDynPropose:
×
UNCOV
129
                return "DynPropose"
×
UNCOV
130
        case MsgDynAck:
×
UNCOV
131
                return "DynAck"
×
UNCOV
132
        case MsgDynReject:
×
UNCOV
133
                return "DynReject"
×
UNCOV
134
        case MsgKickoffSig:
×
UNCOV
135
                return "KickoffSig"
×
136
        case MsgUpdateAddHTLC:
3✔
137
                return "UpdateAddHTLC"
3✔
138
        case MsgUpdateFailHTLC:
3✔
139
                return "UpdateFailHTLC"
3✔
140
        case MsgUpdateFulfillHTLC:
3✔
141
                return "UpdateFulfillHTLC"
3✔
142
        case MsgCommitSig:
3✔
143
                return "CommitSig"
3✔
144
        case MsgRevokeAndAck:
3✔
145
                return "RevokeAndAck"
3✔
146
        case MsgUpdateFailMalformedHTLC:
3✔
147
                return "UpdateFailMalformedHTLC"
3✔
148
        case MsgChannelReestablish:
3✔
149
                return "ChannelReestablish"
3✔
150
        case MsgError:
3✔
151
                return "Error"
3✔
152
        case MsgChannelAnnouncement:
3✔
153
                return "ChannelAnnouncement"
3✔
154
        case MsgChannelUpdate:
3✔
155
                return "ChannelUpdate"
3✔
156
        case MsgNodeAnnouncement:
3✔
157
                return "NodeAnnouncement"
3✔
UNCOV
158
        case MsgPing:
×
UNCOV
159
                return "Ping"
×
160
        case MsgAnnounceSignatures:
3✔
161
                return "AnnounceSignatures"
3✔
UNCOV
162
        case MsgPong:
×
UNCOV
163
                return "Pong"
×
UNCOV
164
        case MsgUpdateFee:
×
UNCOV
165
                return "UpdateFee"
×
166
        case MsgQueryShortChanIDs:
3✔
167
                return "QueryShortChanIDs"
3✔
168
        case MsgReplyShortChanIDsEnd:
3✔
169
                return "ReplyShortChanIDsEnd"
3✔
170
        case MsgQueryChannelRange:
3✔
171
                return "QueryChannelRange"
3✔
172
        case MsgReplyChannelRange:
3✔
173
                return "ReplyChannelRange"
3✔
174
        case MsgGossipTimestampRange:
3✔
175
                return "GossipTimestampRange"
3✔
UNCOV
176
        case MsgClosingComplete:
×
UNCOV
177
                return "ClosingComplete"
×
UNCOV
178
        case MsgClosingSig:
×
UNCOV
179
                return "ClosingSig"
×
UNCOV
180
        case MsgAnnounceSignatures2:
×
UNCOV
181
                return "MsgAnnounceSignatures2"
×
UNCOV
182
        case MsgChannelAnnouncement2:
×
UNCOV
183
                return "ChannelAnnouncement2"
×
UNCOV
184
        case MsgChannelUpdate2:
×
UNCOV
185
                return "ChannelUpdate2"
×
186
        default:
3✔
187
                return "<unknown>"
3✔
188
        }
189
}
190

191
// UnknownMessage is an implementation of the error interface that allows the
192
// creation of an error in response to an unknown message.
193
type UnknownMessage struct {
194
        messageType MessageType
195
}
196

197
// Error returns a human readable string describing the error.
198
//
199
// This is part of the error interface.
200
func (u *UnknownMessage) Error() string {
3✔
201
        return fmt.Sprintf("unable to parse message of unknown type: %v",
3✔
202
                u.messageType)
3✔
203
}
3✔
204

205
// Serializable is an interface which defines a lightning wire serializable
206
// object.
207
type Serializable interface {
208
        // Decode reads the bytes stream and converts it to the object.
209
        Decode(io.Reader, uint32) error
210

211
        // Encode converts object to the bytes stream and write it into the
212
        // write buffer.
213
        Encode(*bytes.Buffer, uint32) error
214
}
215

216
// Message is an interface that defines a lightning wire protocol message. The
217
// interface is general in order to allow implementing types full control over
218
// the representation of its data.
219
type Message interface {
220
        Serializable
221
        MsgType() MessageType
222
}
223

224
// LinkUpdater is an interface implemented by most messages in BOLT 2 that are
225
// allowed to update the channel state.
226
type LinkUpdater interface {
227
        // All LinkUpdater messages are messages and so we embed the interface
228
        // so that we can treat it as a message if all we know about it is that
229
        // it is a LinkUpdater message.
230
        Message
231

232
        // TargetChanID returns the channel id of the link for which this
233
        // message is intended.
234
        TargetChanID() ChannelID
235
}
236

237
// makeEmptyMessage creates a new empty message of the proper concrete type
238
// based on the passed message type.
239
func makeEmptyMessage(msgType MessageType) (Message, error) {
3✔
240
        var msg Message
3✔
241

3✔
242
        switch msgType {
3✔
UNCOV
243
        case MsgWarning:
×
UNCOV
244
                msg = &Warning{}
×
245
        case MsgStfu:
3✔
246
                msg = &Stfu{}
3✔
247
        case MsgInit:
3✔
248
                msg = &Init{}
3✔
249
        case MsgOpenChannel:
3✔
250
                msg = &OpenChannel{}
3✔
251
        case MsgAcceptChannel:
3✔
252
                msg = &AcceptChannel{}
3✔
253
        case MsgFundingCreated:
3✔
254
                msg = &FundingCreated{}
3✔
255
        case MsgFundingSigned:
3✔
256
                msg = &FundingSigned{}
3✔
257
        case MsgChannelReady:
3✔
258
                msg = &ChannelReady{}
3✔
259
        case MsgShutdown:
3✔
260
                msg = &Shutdown{}
3✔
261
        case MsgClosingSigned:
3✔
262
                msg = &ClosingSigned{}
3✔
UNCOV
263
        case MsgDynPropose:
×
UNCOV
264
                msg = &DynPropose{}
×
UNCOV
265
        case MsgDynAck:
×
UNCOV
266
                msg = &DynAck{}
×
UNCOV
267
        case MsgDynReject:
×
UNCOV
268
                msg = &DynReject{}
×
UNCOV
269
        case MsgKickoffSig:
×
UNCOV
270
                msg = &KickoffSig{}
×
271
        case MsgUpdateAddHTLC:
3✔
272
                msg = &UpdateAddHTLC{}
3✔
273
        case MsgUpdateFailHTLC:
3✔
274
                msg = &UpdateFailHTLC{}
3✔
275
        case MsgUpdateFulfillHTLC:
3✔
276
                msg = &UpdateFulfillHTLC{}
3✔
277
        case MsgCommitSig:
3✔
278
                msg = &CommitSig{}
3✔
279
        case MsgRevokeAndAck:
3✔
280
                msg = &RevokeAndAck{}
3✔
UNCOV
281
        case MsgUpdateFee:
×
UNCOV
282
                msg = &UpdateFee{}
×
283
        case MsgUpdateFailMalformedHTLC:
3✔
284
                msg = &UpdateFailMalformedHTLC{}
3✔
285
        case MsgChannelReestablish:
3✔
286
                msg = &ChannelReestablish{}
3✔
287
        case MsgError:
3✔
288
                msg = &Error{}
3✔
289
        case MsgChannelAnnouncement:
3✔
290
                msg = &ChannelAnnouncement1{}
3✔
291
        case MsgChannelUpdate:
3✔
292
                msg = &ChannelUpdate1{}
3✔
293
        case MsgNodeAnnouncement:
3✔
294
                msg = &NodeAnnouncement{}
3✔
UNCOV
295
        case MsgPing:
×
UNCOV
296
                msg = &Ping{}
×
297
        case MsgAnnounceSignatures:
3✔
298
                msg = &AnnounceSignatures1{}
3✔
UNCOV
299
        case MsgPong:
×
UNCOV
300
                msg = &Pong{}
×
301
        case MsgQueryShortChanIDs:
3✔
302
                msg = &QueryShortChanIDs{}
3✔
303
        case MsgReplyShortChanIDsEnd:
3✔
304
                msg = &ReplyShortChanIDsEnd{}
3✔
305
        case MsgQueryChannelRange:
3✔
306
                msg = &QueryChannelRange{}
3✔
307
        case MsgReplyChannelRange:
3✔
308
                msg = &ReplyChannelRange{}
3✔
309
        case MsgGossipTimestampRange:
3✔
310
                msg = &GossipTimestampRange{}
3✔
UNCOV
311
        case MsgClosingComplete:
×
UNCOV
312
                msg = &ClosingComplete{}
×
UNCOV
313
        case MsgClosingSig:
×
UNCOV
314
                msg = &ClosingSig{}
×
UNCOV
315
        case MsgAnnounceSignatures2:
×
UNCOV
316
                msg = &AnnounceSignatures2{}
×
UNCOV
317
        case MsgChannelAnnouncement2:
×
UNCOV
318
                msg = &ChannelAnnouncement2{}
×
UNCOV
319
        case MsgChannelUpdate2:
×
UNCOV
320
                msg = &ChannelUpdate2{}
×
321
        default:
3✔
322
                // If the message is not within our custom range and has not
3✔
323
                // specifically been overridden, return an unknown message.
3✔
324
                //
3✔
325
                // Note that we do not allow custom message overrides to replace
3✔
326
                // known message types, only protocol messages that are not yet
3✔
327
                // known to lnd.
3✔
328
                if msgType < CustomTypeStart && !IsCustomOverride(msgType) {
6✔
329
                        return nil, &UnknownMessage{msgType}
3✔
330
                }
3✔
331

332
                msg = &Custom{
3✔
333
                        Type: msgType,
3✔
334
                }
3✔
335
        }
336

337
        return msg, nil
3✔
338
}
339

340
// WriteMessage writes a lightning Message to a buffer including the necessary
341
// header information and returns the number of bytes written. If any error is
342
// encountered, the buffer passed will be reset to its original state since we
343
// don't want any broken bytes left. In other words, no bytes will be written
344
// if there's an error. Either all or none of the message bytes will be written
345
// to the buffer.
346
//
347
// NOTE: this method is not concurrent safe.
348
func WriteMessage(buf *bytes.Buffer, msg Message, pver uint32) (int, error) {
3✔
349
        // Record the size of the bytes already written in buffer.
3✔
350
        oldByteSize := buf.Len()
3✔
351

3✔
352
        // cleanBrokenBytes is a helper closure that helps reset the buffer to
3✔
353
        // its original state. It truncates all the bytes written in current
3✔
354
        // scope.
3✔
355
        var cleanBrokenBytes = func(b *bytes.Buffer) int {
3✔
UNCOV
356
                b.Truncate(oldByteSize)
×
UNCOV
357
                return 0
×
UNCOV
358
        }
×
359

360
        // Write the message type.
361
        var mType [2]byte
3✔
362
        binary.BigEndian.PutUint16(mType[:], uint16(msg.MsgType()))
3✔
363
        msgTypeBytes, err := buf.Write(mType[:])
3✔
364
        if err != nil {
3✔
365
                return cleanBrokenBytes(buf), ErrorWriteMessageType(err)
×
366
        }
×
367

368
        // Use the write buffer to encode our message.
369
        if err := msg.Encode(buf, pver); err != nil {
3✔
UNCOV
370
                return cleanBrokenBytes(buf), ErrorEncodeMessage(err)
×
UNCOV
371
        }
×
372

373
        // Enforce maximum overall message payload. The write buffer now has
374
        // the size of len(originalBytes) + len(payload) + len(type). We want
375
        // to enforce the payload here, so we subtract it by the length of the
376
        // type and old bytes.
377
        lenp := buf.Len() - oldByteSize - msgTypeBytes
3✔
378
        if lenp > MaxMsgBody {
3✔
UNCOV
379
                return cleanBrokenBytes(buf), ErrorPayloadTooLarge(lenp)
×
UNCOV
380
        }
×
381

382
        return buf.Len() - oldByteSize, nil
3✔
383
}
384

385
// ReadMessage reads, validates, and parses the next Lightning message from r
386
// for the provided protocol version.
387
func ReadMessage(r io.Reader, pver uint32) (Message, error) {
3✔
388
        // First, we'll read out the first two bytes of the message so we can
3✔
389
        // create the proper empty message.
3✔
390
        var mType [2]byte
3✔
391
        if _, err := io.ReadFull(r, mType[:]); err != nil {
3✔
392
                return nil, err
×
393
        }
×
394

395
        msgType := MessageType(binary.BigEndian.Uint16(mType[:]))
3✔
396

3✔
397
        // Now that we know the target message type, we can create the proper
3✔
398
        // empty message type and decode the message into it.
3✔
399
        msg, err := makeEmptyMessage(msgType)
3✔
400
        if err != nil {
6✔
401
                return nil, err
3✔
402
        }
3✔
403
        if err := msg.Decode(r, pver); err != nil {
3✔
UNCOV
404
                return nil, err
×
UNCOV
405
        }
×
406

407
        return msg, nil
3✔
408
}
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