• 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

73.2
/watchtower/wtwire/message.go
1
package wtwire
2

3
import (
4
        "bytes"
5
        "encoding/binary"
6
        "fmt"
7
        "io"
8
)
9

10
// MaxMessagePayload is the maximum bytes a message can be regardless of other
11
// individual limits imposed by messages themselves.
12
const MaxMessagePayload = 65535 // 65KB
13

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

21
// The currently defined message types within this current version of the
22
// Watchtower protocol.
23
const (
24
        // MsgInit identifies an encoded Init message.
25
        MsgInit MessageType = 600
26

27
        // MsgError identifies an encoded Error message.
28
        MsgError MessageType = 601
29

30
        // MsgCreateSession identifies an encoded CreateSession message.
31
        MsgCreateSession MessageType = 602
32

33
        // MsgCreateSessionReply identifies an encoded CreateSessionReply message.
34
        MsgCreateSessionReply MessageType = 603
35

36
        // MsgStateUpdate identifies an encoded StateUpdate message.
37
        MsgStateUpdate MessageType = 604
38

39
        // MsgStateUpdateReply identifies an encoded StateUpdateReply message.
40
        MsgStateUpdateReply MessageType = 605
41

42
        // MsgDeleteSession identifies an encoded DeleteSession message.
43
        MsgDeleteSession MessageType = 606
44

45
        // MsgDeleteSessionReply identifies an encoded DeleteSessionReply
46
        // message.
47
        MsgDeleteSessionReply MessageType = 607
48
)
49

50
// String returns a human readable description of the message type.
51
func (m MessageType) String() string {
3✔
52
        switch m {
3✔
53
        case MsgInit:
3✔
54
                return "Init"
3✔
55
        case MsgCreateSession:
3✔
56
                return "MsgCreateSession"
3✔
57
        case MsgCreateSessionReply:
3✔
58
                return "MsgCreateSessionReply"
3✔
59
        case MsgStateUpdate:
3✔
60
                return "MsgStateUpdate"
3✔
61
        case MsgStateUpdateReply:
3✔
62
                return "MsgStateUpdateReply"
3✔
63
        case MsgDeleteSession:
3✔
64
                return "MsgDeleteSession"
3✔
65
        case MsgDeleteSessionReply:
3✔
66
                return "MsgDeleteSessionReply"
3✔
UNCOV
67
        case MsgError:
×
UNCOV
68
                return "Error"
×
69
        default:
×
70
                return "<unknown>"
×
71
        }
72
}
73

74
// Serializable is an interface which defines a lightning wire serializable
75
// object.
76
type Serializable interface {
77
        // Decode reads the bytes stream and converts it to the object.
78
        Decode(io.Reader, uint32) error
79

80
        // Encode converts object to the bytes stream and write it into the
81
        // write buffer.
82
        Encode(io.Writer, uint32) error
83
}
84

85
// Message is an interface that defines a lightning wire protocol message. The
86
// interface is general in order to allow implementing types full control over
87
// the representation of its data.
88
type Message interface {
89
        Serializable
90

91
        // MsgType returns a MessageType that uniquely identifies the message to
92
        // be encoded.
93
        MsgType() MessageType
94

95
        // MaxPayloadLength is the maximum serialized length that a particular
96
        // message type can take.
97
        MaxPayloadLength(uint32) uint32
98
}
99

100
// makeEmptyMessage creates a new empty message of the proper concrete type
101
// based on the passed message type.
102
func makeEmptyMessage(msgType MessageType) (Message, error) {
3✔
103
        var msg Message
3✔
104

3✔
105
        switch msgType {
3✔
106
        case MsgInit:
3✔
107
                msg = &Init{}
3✔
108
        case MsgCreateSession:
3✔
109
                msg = &CreateSession{}
3✔
110
        case MsgCreateSessionReply:
3✔
111
                msg = &CreateSessionReply{}
3✔
112
        case MsgStateUpdate:
3✔
113
                msg = &StateUpdate{}
3✔
114
        case MsgStateUpdateReply:
3✔
115
                msg = &StateUpdateReply{}
3✔
116
        case MsgDeleteSession:
3✔
117
                msg = &DeleteSession{}
3✔
118
        case MsgDeleteSessionReply:
3✔
119
                msg = &DeleteSessionReply{}
3✔
UNCOV
120
        case MsgError:
×
UNCOV
121
                msg = &Error{}
×
122
        default:
×
123
                return nil, fmt.Errorf("unknown message type [%d]", msgType)
×
124
        }
125

126
        return msg, nil
3✔
127
}
128

129
// WriteMessage writes a lightning Message to w including the necessary header
130
// information and returns the number of bytes written.
131
func WriteMessage(w io.Writer, msg Message, pver uint32) (int, error) {
3✔
132
        totalBytes := 0
3✔
133

3✔
134
        // Encode the message payload itself into a temporary buffer.
3✔
135
        // TODO(roasbeef): create buffer pool
3✔
136
        var bw bytes.Buffer
3✔
137
        if err := msg.Encode(&bw, pver); err != nil {
3✔
138
                return totalBytes, err
×
139
        }
×
140
        payload := bw.Bytes()
3✔
141
        lenp := len(payload)
3✔
142

3✔
143
        // Enforce maximum overall message payload.
3✔
144
        if lenp > MaxMessagePayload {
3✔
145
                return totalBytes, fmt.Errorf("message payload is too large - "+
×
146
                        "encoded %d bytes, but maximum message payload is %d bytes",
×
147
                        lenp, MaxMessagePayload)
×
148
        }
×
149

150
        // Enforce maximum message payload on the message type.
151
        mpl := msg.MaxPayloadLength(pver)
3✔
152
        if uint32(lenp) > mpl {
3✔
153
                return totalBytes, fmt.Errorf("message payload is too large - "+
×
154
                        "encoded %d bytes, but maximum message payload of "+
×
155
                        "type %v is %d bytes", lenp, msg.MsgType(), mpl)
×
156
        }
×
157

158
        // With the initial sanity checks complete, we'll now write out the
159
        // message type itself.
160
        var mType [2]byte
3✔
161
        binary.BigEndian.PutUint16(mType[:], uint16(msg.MsgType()))
3✔
162
        n, err := w.Write(mType[:])
3✔
163
        totalBytes += n
3✔
164
        if err != nil {
3✔
165
                return totalBytes, err
×
166
        }
×
167

168
        // With the message type written, we'll now write out the raw payload
169
        // itself.
170
        n, err = w.Write(payload)
3✔
171
        totalBytes += n
3✔
172

3✔
173
        return totalBytes, err
3✔
174
}
175

176
// ReadMessage reads, validates, and parses the next Watchtower message from r
177
// for the provided protocol version.
178
func ReadMessage(r io.Reader, pver uint32) (Message, error) {
3✔
179
        // First, we'll read out the first two bytes of the message so we can
3✔
180
        // create the proper empty message.
3✔
181
        var mType [2]byte
3✔
182
        if _, err := io.ReadFull(r, mType[:]); err != nil {
3✔
183
                return nil, err
×
184
        }
×
185

186
        msgType := MessageType(binary.BigEndian.Uint16(mType[:]))
3✔
187

3✔
188
        // Now that we know the target message type, we can create the proper
3✔
189
        // empty message type and decode the message into it.
3✔
190
        msg, err := makeEmptyMessage(msgType)
3✔
191
        if err != nil {
3✔
192
                return nil, err
×
193
        }
×
194
        if err := msg.Decode(r, pver); err != nil {
3✔
UNCOV
195
                return nil, err
×
UNCOV
196
        }
×
197

198
        return msg, nil
3✔
199
}
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