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

lightningnetwork / lnd / 16154950206

08 Jul 2025 09:39PM UTC coverage: 57.703% (-9.8%) from 67.503%
16154950206

Pull #10049

github

web-flow
Merge d46a710c1 into 47dce0894
Pull Request #10049: multi: prevent duplicates for locally dispatched HTLC attempts

88 of 123 new or added lines in 4 files covered. (71.54%)

28463 existing lines in 454 files now uncovered.

98524 of 170743 relevant lines covered (57.7%)

1.79 hits per line

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

69.49
/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
// MessageTypeSize is the size in bytes of the message type field in the header
16
// of all messages.
17
const MessageTypeSize = 2
18

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

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

70
        // MsgPendingNetworkResult is an internal message used by the Switch
71
        // network result store as a place holder when initializing an HTLC
72
        // attempt within the store. It will not be received from network peers.
73
        MsgPendingNetworkResult = 0xffff
74

75
        // MsgEnd defines the end of the official message range of the protocol.
76
        // If a new message is added beyond this message, then this should be
77
        // modified.
78
        MsgEnd = 778
79
)
80

81
// IsChannelUpdate is a filter function that discerns channel update messages
82
// from the other messages in the Lightning Network Protocol.
83
func (t MessageType) IsChannelUpdate() bool {
3✔
84
        switch t {
3✔
85
        case MsgUpdateAddHTLC:
3✔
86
                return true
3✔
87
        case MsgUpdateFulfillHTLC:
3✔
88
                return true
3✔
89
        case MsgUpdateFailHTLC:
3✔
90
                return true
3✔
91
        case MsgUpdateFailMalformedHTLC:
3✔
92
                return true
3✔
UNCOV
93
        case MsgUpdateFee:
×
UNCOV
94
                return true
×
95
        default:
3✔
96
                return false
3✔
97
        }
98
}
99

100
// ErrorEncodeMessage is used when failed to encode the message payload.
UNCOV
101
func ErrorEncodeMessage(err error) error {
×
UNCOV
102
        return fmt.Errorf("failed to encode message to buffer, got %w", err)
×
UNCOV
103
}
×
104

105
// ErrorWriteMessageType is used when failed to write the message type.
106
func ErrorWriteMessageType(err error) error {
×
107
        return fmt.Errorf("failed to write message type, got %w", err)
×
108
}
×
109

110
// ErrorPayloadTooLarge is used when the payload size exceeds the
111
// MaxMsgBody.
UNCOV
112
func ErrorPayloadTooLarge(size int) error {
×
UNCOV
113
        return fmt.Errorf(
×
UNCOV
114
                "message payload is too large - encoded %d bytes, "+
×
UNCOV
115
                        "but maximum message payload is %d bytes",
×
UNCOV
116
                size, MaxMsgBody,
×
UNCOV
117
        )
×
UNCOV
118
}
×
119

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

210
// UnknownMessage is an implementation of the error interface that allows the
211
// creation of an error in response to an unknown message.
212
type UnknownMessage struct {
213
        messageType MessageType
214
}
215

216
// Error returns a human readable string describing the error.
217
//
218
// This is part of the error interface.
219
func (u *UnknownMessage) Error() string {
3✔
220
        return fmt.Sprintf("unable to parse message of unknown type: %v",
3✔
221
                u.messageType)
3✔
222
}
3✔
223

224
// Serializable is an interface which defines a lightning wire serializable
225
// object.
226
type Serializable interface {
227
        // Decode reads the bytes stream and converts it to the object.
228
        Decode(io.Reader, uint32) error
229

230
        // Encode converts object to the bytes stream and write it into the
231
        // write buffer.
232
        Encode(*bytes.Buffer, uint32) error
233
}
234

235
// Message is an interface that defines a lightning wire protocol message. The
236
// interface is general in order to allow implementing types full control over
237
// the representation of its data.
238
type Message interface {
239
        Serializable
240
        MsgType() MessageType
241
}
242

243
// LinkUpdater is an interface implemented by most messages in BOLT 2 that are
244
// allowed to update the channel state.
245
type LinkUpdater interface {
246
        // All LinkUpdater messages are messages and so we embed the interface
247
        // so that we can treat it as a message if all we know about it is that
248
        // it is a LinkUpdater message.
249
        Message
250

251
        // TargetChanID returns the channel id of the link for which this
252
        // message is intended.
253
        TargetChanID() ChannelID
254
}
255

256
// SizeableMessage is an interface that extends the base Message interface with
257
// a method to calculate the serialized size of a message.
258
type SizeableMessage interface {
259
        Message
260

261
        // SerializedSize returns the serialized size of the message in bytes.
262
        // The returned size includes the message type header bytes.
263
        SerializedSize() (uint32, error)
264
}
265

266
// MessageSerializedSize calculates the serialized size of a message in bytes.
267
// This is a helper function that can be used by all message types to implement
268
// the SerializedSize method.
269
func MessageSerializedSize(msg Message) (uint32, error) {
3✔
270
        var buf bytes.Buffer
3✔
271

3✔
272
        // Encode the message to the buffer.
3✔
273
        if err := msg.Encode(&buf, 0); err != nil {
3✔
274
                return 0, err
×
275
        }
×
276

277
        // Add the size of the message type.
278
        return uint32(buf.Len()) + MessageTypeSize, nil
3✔
279
}
280

281
// makeEmptyMessage creates a new empty message of the proper concrete type
282
// based on the passed message type.
283
func makeEmptyMessage(msgType MessageType) (Message, error) {
3✔
284
        var msg Message
3✔
285

3✔
286
        switch msgType {
3✔
UNCOV
287
        case MsgWarning:
×
UNCOV
288
                msg = &Warning{}
×
289
        case MsgStfu:
3✔
290
                msg = &Stfu{}
3✔
291
        case MsgInit:
3✔
292
                msg = &Init{}
3✔
293
        case MsgOpenChannel:
3✔
294
                msg = &OpenChannel{}
3✔
295
        case MsgAcceptChannel:
3✔
296
                msg = &AcceptChannel{}
3✔
297
        case MsgFundingCreated:
3✔
298
                msg = &FundingCreated{}
3✔
299
        case MsgFundingSigned:
3✔
300
                msg = &FundingSigned{}
3✔
301
        case MsgChannelReady:
3✔
302
                msg = &ChannelReady{}
3✔
303
        case MsgShutdown:
3✔
304
                msg = &Shutdown{}
3✔
305
        case MsgClosingSigned:
3✔
306
                msg = &ClosingSigned{}
3✔
UNCOV
307
        case MsgDynPropose:
×
UNCOV
308
                msg = &DynPropose{}
×
UNCOV
309
        case MsgDynAck:
×
UNCOV
310
                msg = &DynAck{}
×
UNCOV
311
        case MsgDynReject:
×
UNCOV
312
                msg = &DynReject{}
×
UNCOV
313
        case MsgDynCommit:
×
UNCOV
314
                msg = &DynCommit{}
×
UNCOV
315
        case MsgKickoffSig:
×
UNCOV
316
                msg = &KickoffSig{}
×
317
        case MsgUpdateAddHTLC:
3✔
318
                msg = &UpdateAddHTLC{}
3✔
319
        case MsgUpdateFailHTLC:
3✔
320
                msg = &UpdateFailHTLC{}
3✔
321
        case MsgUpdateFulfillHTLC:
3✔
322
                msg = &UpdateFulfillHTLC{}
3✔
323
        case MsgCommitSig:
3✔
324
                msg = &CommitSig{}
3✔
325
        case MsgRevokeAndAck:
3✔
326
                msg = &RevokeAndAck{}
3✔
UNCOV
327
        case MsgUpdateFee:
×
UNCOV
328
                msg = &UpdateFee{}
×
329
        case MsgUpdateFailMalformedHTLC:
3✔
330
                msg = &UpdateFailMalformedHTLC{}
3✔
331
        case MsgChannelReestablish:
3✔
332
                msg = &ChannelReestablish{}
3✔
333
        case MsgError:
3✔
334
                msg = &Error{}
3✔
335
        case MsgChannelAnnouncement:
3✔
336
                msg = &ChannelAnnouncement1{}
3✔
337
        case MsgChannelUpdate:
3✔
338
                msg = &ChannelUpdate1{}
3✔
339
        case MsgNodeAnnouncement:
3✔
340
                msg = &NodeAnnouncement{}
3✔
UNCOV
341
        case MsgPing:
×
UNCOV
342
                msg = &Ping{}
×
343
        case MsgAnnounceSignatures:
3✔
344
                msg = &AnnounceSignatures1{}
3✔
UNCOV
345
        case MsgPong:
×
UNCOV
346
                msg = &Pong{}
×
347
        case MsgQueryShortChanIDs:
3✔
348
                msg = &QueryShortChanIDs{}
3✔
349
        case MsgReplyShortChanIDsEnd:
3✔
350
                msg = &ReplyShortChanIDsEnd{}
3✔
351
        case MsgQueryChannelRange:
3✔
352
                msg = &QueryChannelRange{}
3✔
353
        case MsgReplyChannelRange:
3✔
354
                msg = &ReplyChannelRange{}
3✔
355
        case MsgGossipTimestampRange:
3✔
356
                msg = &GossipTimestampRange{}
3✔
357
        case MsgClosingComplete:
3✔
358
                msg = &ClosingComplete{}
3✔
359
        case MsgClosingSig:
3✔
360
                msg = &ClosingSig{}
3✔
UNCOV
361
        case MsgAnnounceSignatures2:
×
UNCOV
362
                msg = &AnnounceSignatures2{}
×
UNCOV
363
        case MsgChannelAnnouncement2:
×
UNCOV
364
                msg = &ChannelAnnouncement2{}
×
UNCOV
365
        case MsgChannelUpdate2:
×
UNCOV
366
                msg = &ChannelUpdate2{}
×
367
        case MsgPendingNetworkResult:
3✔
368
                msg = &PendingNetworkResult{}
3✔
369
        default:
3✔
370
                // If the message is not within our custom range and has not
3✔
371
                // specifically been overridden, return an unknown message.
3✔
372
                //
3✔
373
                // Note that we do not allow custom message overrides to replace
3✔
374
                // known message types, only protocol messages that are not yet
3✔
375
                // known to lnd.
3✔
376
                if msgType < CustomTypeStart && !IsCustomOverride(msgType) {
6✔
377
                        return nil, &UnknownMessage{msgType}
3✔
378
                }
3✔
379

380
                msg = &Custom{
3✔
381
                        Type: msgType,
3✔
382
                }
3✔
383
        }
384

385
        return msg, nil
3✔
386
}
387

388
// MakeEmptyMessage creates a new empty message of the proper concrete type
389
// based on the passed message type. This is exported to be used in tests.
UNCOV
390
func MakeEmptyMessage(msgType MessageType) (Message, error) {
×
UNCOV
391
        return makeEmptyMessage(msgType)
×
UNCOV
392
}
×
393

394
// WriteMessage writes a lightning Message to a buffer including the necessary
395
// header information and returns the number of bytes written. If any error is
396
// encountered, the buffer passed will be reset to its original state since we
397
// don't want any broken bytes left. In other words, no bytes will be written
398
// if there's an error. Either all or none of the message bytes will be written
399
// to the buffer.
400
//
401
// NOTE: this method is not concurrent safe.
402
func WriteMessage(buf *bytes.Buffer, msg Message, pver uint32) (int, error) {
3✔
403
        // Record the size of the bytes already written in buffer.
3✔
404
        oldByteSize := buf.Len()
3✔
405

3✔
406
        // cleanBrokenBytes is a helper closure that helps reset the buffer to
3✔
407
        // its original state. It truncates all the bytes written in current
3✔
408
        // scope.
3✔
409
        var cleanBrokenBytes = func(b *bytes.Buffer) int {
3✔
UNCOV
410
                b.Truncate(oldByteSize)
×
UNCOV
411
                return 0
×
UNCOV
412
        }
×
413

414
        // Write the message type.
415
        var mType [2]byte
3✔
416
        binary.BigEndian.PutUint16(mType[:], uint16(msg.MsgType()))
3✔
417
        msgTypeBytes, err := buf.Write(mType[:])
3✔
418
        if err != nil {
3✔
419
                return cleanBrokenBytes(buf), ErrorWriteMessageType(err)
×
420
        }
×
421

422
        // Use the write buffer to encode our message.
423
        if err := msg.Encode(buf, pver); err != nil {
3✔
UNCOV
424
                return cleanBrokenBytes(buf), ErrorEncodeMessage(err)
×
UNCOV
425
        }
×
426

427
        // Enforce maximum overall message payload. The write buffer now has
428
        // the size of len(originalBytes) + len(payload) + len(type). We want
429
        // to enforce the payload here, so we subtract it by the length of the
430
        // type and old bytes.
431
        lenp := buf.Len() - oldByteSize - msgTypeBytes
3✔
432
        if lenp > MaxMsgBody {
3✔
UNCOV
433
                return cleanBrokenBytes(buf), ErrorPayloadTooLarge(lenp)
×
UNCOV
434
        }
×
435

436
        return buf.Len() - oldByteSize, nil
3✔
437
}
438

439
// ReadMessage reads, validates, and parses the next Lightning message from r
440
// for the provided protocol version.
441
func ReadMessage(r io.Reader, pver uint32) (Message, error) {
3✔
442
        // First, we'll read out the first two bytes of the message so we can
3✔
443
        // create the proper empty message.
3✔
444
        var mType [2]byte
3✔
445
        if _, err := io.ReadFull(r, mType[:]); err != nil {
3✔
446
                return nil, err
×
447
        }
×
448

449
        msgType := MessageType(binary.BigEndian.Uint16(mType[:]))
3✔
450

3✔
451
        // Now that we know the target message type, we can create the proper
3✔
452
        // empty message type and decode the message into it.
3✔
453
        msg, err := makeEmptyMessage(msgType)
3✔
454
        if err != nil {
6✔
455
                return nil, err
3✔
456
        }
3✔
457
        if err := msg.Decode(r, pver); err != nil {
3✔
UNCOV
458
                return nil, err
×
UNCOV
459
        }
×
460

461
        return msg, nil
3✔
462
}
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