-
Notifications
You must be signed in to change notification settings - Fork 2.1k
/
message.go
314 lines (288 loc) · 9.24 KB
/
message.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
// Copyright (c) 2013-2017 The btcsuite developers
// Copyright (c) 2015-2016 The Decred developers
// code derived from https://github .com/btcsuite/btcd/blob/master/wire/message.go
// Copyright (C) 2015-2022 The Lightning Network Developers
package lnwire
import (
"bytes"
"encoding/binary"
"fmt"
"io"
)
// MessageType is the unique 2 byte big-endian integer that indicates the type
// of message on the wire. All messages have a very simple header which
// consists simply of 2-byte message type. We omit a length field, and checksum
// as the Lightning Protocol is intended to be encapsulated within a
// confidential+authenticated cryptographic messaging protocol.
type MessageType uint16
// The currently defined message types within this current version of the
// Lightning protocol.
const (
MsgInit MessageType = 16
MsgError = 17
MsgPing = 18
MsgPong = 19
MsgOpenChannel = 32
MsgAcceptChannel = 33
MsgFundingCreated = 34
MsgFundingSigned = 35
MsgFundingLocked = 36
MsgShutdown = 38
MsgClosingSigned = 39
MsgUpdateAddHTLC = 128
MsgUpdateFulfillHTLC = 130
MsgUpdateFailHTLC = 131
MsgCommitSig = 132
MsgRevokeAndAck = 133
MsgUpdateFee = 134
MsgUpdateFailMalformedHTLC = 135
MsgChannelReestablish = 136
MsgChannelAnnouncement = 256
MsgNodeAnnouncement = 257
MsgChannelUpdate = 258
MsgAnnounceSignatures = 259
MsgQueryShortChanIDs = 261
MsgReplyShortChanIDsEnd = 262
MsgQueryChannelRange = 263
MsgReplyChannelRange = 264
MsgGossipTimestampRange = 265
)
// ErrorEncodeMessage is used when failed to encode the message payload.
func ErrorEncodeMessage(err error) error {
return fmt.Errorf("failed to encode message to buffer, got %w", err)
}
// ErrorWriteMessageType is used when failed to write the message type.
func ErrorWriteMessageType(err error) error {
return fmt.Errorf("failed to write message type, got %w", err)
}
// ErrorPayloadTooLarge is used when the payload size exceeds the
// MaxMsgBody.
func ErrorPayloadTooLarge(size int) error {
return fmt.Errorf(
"message payload is too large - encoded %d bytes, "+
"but maximum message payload is %d bytes",
size, MaxMsgBody,
)
}
// String return the string representation of message type.
func (t MessageType) String() string {
switch t {
case MsgInit:
return "Init"
case MsgOpenChannel:
return "MsgOpenChannel"
case MsgAcceptChannel:
return "MsgAcceptChannel"
case MsgFundingCreated:
return "MsgFundingCreated"
case MsgFundingSigned:
return "MsgFundingSigned"
case MsgFundingLocked:
return "FundingLocked"
case MsgShutdown:
return "Shutdown"
case MsgClosingSigned:
return "ClosingSigned"
case MsgUpdateAddHTLC:
return "UpdateAddHTLC"
case MsgUpdateFailHTLC:
return "UpdateFailHTLC"
case MsgUpdateFulfillHTLC:
return "UpdateFulfillHTLC"
case MsgCommitSig:
return "CommitSig"
case MsgRevokeAndAck:
return "RevokeAndAck"
case MsgUpdateFailMalformedHTLC:
return "UpdateFailMalformedHTLC"
case MsgChannelReestablish:
return "ChannelReestablish"
case MsgError:
return "Error"
case MsgChannelAnnouncement:
return "ChannelAnnouncement"
case MsgChannelUpdate:
return "ChannelUpdate"
case MsgNodeAnnouncement:
return "NodeAnnouncement"
case MsgPing:
return "Ping"
case MsgAnnounceSignatures:
return "AnnounceSignatures"
case MsgPong:
return "Pong"
case MsgUpdateFee:
return "UpdateFee"
case MsgQueryShortChanIDs:
return "QueryShortChanIDs"
case MsgReplyShortChanIDsEnd:
return "ReplyShortChanIDsEnd"
case MsgQueryChannelRange:
return "QueryChannelRange"
case MsgReplyChannelRange:
return "ReplyChannelRange"
case MsgGossipTimestampRange:
return "GossipTimestampRange"
default:
return "<unknown>"
}
}
// UnknownMessage is an implementation of the error interface that allows the
// creation of an error in response to an unknown message.
type UnknownMessage struct {
messageType MessageType
}
// Error returns a human readable string describing the error.
//
// This is part of the error interface.
func (u *UnknownMessage) Error() string {
return fmt.Sprintf("unable to parse message of unknown type: %v",
u.messageType)
}
// Serializable is an interface which defines a lightning wire serializable
// object.
type Serializable interface {
// Decode reads the bytes stream and converts it to the object.
Decode(io.Reader, uint32) error
// Encode converts object to the bytes stream and write it into the
// write buffer.
Encode(*bytes.Buffer, uint32) error
}
// Message is an interface that defines a lightning wire protocol message. The
// interface is general in order to allow implementing types full control over
// the representation of its data.
type Message interface {
Serializable
MsgType() MessageType
}
// makeEmptyMessage creates a new empty message of the proper concrete type
// based on the passed message type.
func makeEmptyMessage(msgType MessageType) (Message, error) {
var msg Message
switch msgType {
case MsgInit:
msg = &Init{}
case MsgOpenChannel:
msg = &OpenChannel{}
case MsgAcceptChannel:
msg = &AcceptChannel{}
case MsgFundingCreated:
msg = &FundingCreated{}
case MsgFundingSigned:
msg = &FundingSigned{}
case MsgFundingLocked:
msg = &FundingLocked{}
case MsgShutdown:
msg = &Shutdown{}
case MsgClosingSigned:
msg = &ClosingSigned{}
case MsgUpdateAddHTLC:
msg = &UpdateAddHTLC{}
case MsgUpdateFailHTLC:
msg = &UpdateFailHTLC{}
case MsgUpdateFulfillHTLC:
msg = &UpdateFulfillHTLC{}
case MsgCommitSig:
msg = &CommitSig{}
case MsgRevokeAndAck:
msg = &RevokeAndAck{}
case MsgUpdateFee:
msg = &UpdateFee{}
case MsgUpdateFailMalformedHTLC:
msg = &UpdateFailMalformedHTLC{}
case MsgChannelReestablish:
msg = &ChannelReestablish{}
case MsgError:
msg = &Error{}
case MsgChannelAnnouncement:
msg = &ChannelAnnouncement{}
case MsgChannelUpdate:
msg = &ChannelUpdate{}
case MsgNodeAnnouncement:
msg = &NodeAnnouncement{}
case MsgPing:
msg = &Ping{}
case MsgAnnounceSignatures:
msg = &AnnounceSignatures{}
case MsgPong:
msg = &Pong{}
case MsgQueryShortChanIDs:
msg = &QueryShortChanIDs{}
case MsgReplyShortChanIDsEnd:
msg = &ReplyShortChanIDsEnd{}
case MsgQueryChannelRange:
msg = &QueryChannelRange{}
case MsgReplyChannelRange:
msg = &ReplyChannelRange{}
case MsgGossipTimestampRange:
msg = &GossipTimestampRange{}
default:
if msgType < CustomTypeStart {
return nil, &UnknownMessage{msgType}
}
msg = &Custom{
Type: msgType,
}
}
return msg, nil
}
// WriteMessage writes a lightning Message to a buffer including the necessary
// header information and returns the number of bytes written. If any error is
// encountered, the buffer passed will be reset to its original state since we
// don't want any broken bytes left. In other words, no bytes will be written
// if there's an error. Either all or none of the message bytes will be written
// to the buffer.
//
// NOTE: this method is not concurrent safe.
func WriteMessage(buf *bytes.Buffer, msg Message, pver uint32) (int, error) {
// Record the size of the bytes already written in buffer.
oldByteSize := buf.Len()
// cleanBrokenBytes is a helper closure that helps reset the buffer to
// its original state. It truncates all the bytes written in current
// scope.
var cleanBrokenBytes = func(b *bytes.Buffer) int {
b.Truncate(oldByteSize)
return 0
}
// Write the message type.
var mType [2]byte
binary.BigEndian.PutUint16(mType[:], uint16(msg.MsgType()))
msgTypeBytes, err := buf.Write(mType[:])
if err != nil {
return cleanBrokenBytes(buf), ErrorWriteMessageType(err)
}
// Use the write buffer to encode our message.
if err := msg.Encode(buf, pver); err != nil {
return cleanBrokenBytes(buf), ErrorEncodeMessage(err)
}
// Enforce maximum overall message payload. The write buffer now has
// the size of len(originalBytes) + len(payload) + len(type). We want
// to enforce the payload here, so we subtract it by the length of the
// type and old bytes.
lenp := buf.Len() - oldByteSize - msgTypeBytes
if lenp > MaxMsgBody {
return cleanBrokenBytes(buf), ErrorPayloadTooLarge(lenp)
}
return buf.Len() - oldByteSize, nil
}
// ReadMessage reads, validates, and parses the next Lightning message from r
// for the provided protocol version.
func ReadMessage(r io.Reader, pver uint32) (Message, error) {
// First, we'll read out the first two bytes of the message so we can
// create the proper empty message.
var mType [2]byte
if _, err := io.ReadFull(r, mType[:]); err != nil {
return nil, err
}
msgType := MessageType(binary.BigEndian.Uint16(mType[:]))
// Now that we know the target message type, we can create the proper
// empty message type and decode the message into it.
msg, err := makeEmptyMessage(msgType)
if err != nil {
return nil, err
}
if err := msg.Decode(r, pver); err != nil {
return nil, err
}
return msg, nil
}