• 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

78.18
/htlcswitch/failure.go
1
package htlcswitch
2

3
import (
4
        "bytes"
5
        "fmt"
6

7
        sphinx "github.com/lightningnetwork/lightning-onion"
8
        "github.com/lightningnetwork/lnd/htlcswitch/hop"
9
        "github.com/lightningnetwork/lnd/lnwire"
10
)
11

12
// ClearTextError is an interface which is implemented by errors that occur
13
// when we know the underlying wire failure message. These errors are the
14
// opposite to opaque errors which are onion-encrypted blobs only understandable
15
// to the initiating node. ClearTextErrors are used when we fail a htlc at our
16
// node, or one of our initiated payments failed and we can decrypt the onion
17
// encrypted error fully.
18
type ClearTextError interface {
19
        error
20

21
        // WireMessage extracts a valid wire failure message from an internal
22
        // error which may contain additional metadata (which should not be
23
        // exposed to the network). This value may be nil in the case where
24
        // an unknown wire error is returned by one of our peers.
25
        WireMessage() lnwire.FailureMessage
26
}
27

28
// LinkError is an implementation of the ClearTextError interface which
29
// represents failures that occur on our incoming or outgoing link.
30
type LinkError struct {
31
        // msg returns the wire failure associated with the error.
32
        // This value should *not* be nil, because we should always
33
        // know the failure type for failures which occur at our own
34
        // node.
35
        msg lnwire.FailureMessage
36

37
        // FailureDetail enriches the wire error with additional information.
38
        FailureDetail
39
}
40

41
// NewLinkError returns a LinkError with the failure message provided.
42
// The failure message provided should *not* be nil, because we should
43
// always know the failure type for failures which occur at our own node.
44
func NewLinkError(msg lnwire.FailureMessage) *LinkError {
3✔
45
        return &LinkError{msg: msg}
3✔
46
}
3✔
47

48
// NewDetailedLinkError returns a link error that enriches a wire message with
49
// a failure detail.
50
func NewDetailedLinkError(msg lnwire.FailureMessage,
51
        detail FailureDetail) *LinkError {
3✔
52

3✔
53
        return &LinkError{
3✔
54
                msg:           msg,
3✔
55
                FailureDetail: detail,
3✔
56
        }
3✔
57
}
3✔
58

59
// WireMessage extracts a valid wire failure message from an internal
60
// error which may contain additional metadata (which should not be
61
// exposed to the network). This value should never be nil for LinkErrors,
62
// because we are the ones failing the htlc.
63
//
64
// Note this is part of the ClearTextError interface.
65
func (l *LinkError) WireMessage() lnwire.FailureMessage {
3✔
66
        return l.msg
3✔
67
}
3✔
68

69
// Error returns the string representation of a link error.
70
//
71
// Note this is part of the ClearTextError interface.
72
func (l *LinkError) Error() string {
3✔
73
        // If the link error has no failure detail, return the wire message's
3✔
74
        // error.
3✔
75
        if l.FailureDetail == nil {
6✔
76
                return l.msg.Error()
3✔
77
        }
3✔
78

79
        return l.FailureDetail.FailureString()
3✔
80
}
81

82
// ForwardingError wraps an lnwire.FailureMessage in a struct that also
83
// includes the source of the error.
84
type ForwardingError struct {
85
        // FailureSourceIdx is the index of the node that sent the failure. With
86
        // this information, the dispatcher of a payment can modify their set of
87
        // candidate routes in response to the type of failure extracted. Index
88
        // zero is the self node.
89
        FailureSourceIdx int
90

91
        // msg is the wire message associated with the error. This value may
92
        // be nil in the case where we fail to decode failure message sent by
93
        // a peer.
94
        msg lnwire.FailureMessage
95
}
96

97
// WireMessage extracts a valid wire failure message from an internal
98
// error which may contain additional metadata (which should not be
99
// exposed to the network). This value may be nil in the case where
100
// an unknown wire error is returned by one of our peers.
101
//
102
// Note this is part of the ClearTextError interface.
103
func (f *ForwardingError) WireMessage() lnwire.FailureMessage {
3✔
104
        return f.msg
3✔
105
}
3✔
106

107
// Error implements the built-in error interface. We use this method to allow
108
// the switch or any callers to insert additional context to the error message
109
// returned.
110
func (f *ForwardingError) Error() string {
3✔
111
        return fmt.Sprintf(
3✔
112
                "%v@%v", f.msg, f.FailureSourceIdx,
3✔
113
        )
3✔
114
}
3✔
115

116
// NewForwardingError creates a new payment error which wraps a wire error
117
// with additional metadata.
118
func NewForwardingError(failure lnwire.FailureMessage,
119
        index int) *ForwardingError {
3✔
120

3✔
121
        return &ForwardingError{
3✔
122
                FailureSourceIdx: index,
3✔
123
                msg:              failure,
3✔
124
        }
3✔
125
}
3✔
126

127
// NewUnknownForwardingError returns a forwarding error which has a nil failure
128
// message. This constructor should only be used in the case where we cannot
129
// decode the failure we have received from a peer.
UNCOV
130
func NewUnknownForwardingError(index int) *ForwardingError {
×
UNCOV
131
        return &ForwardingError{
×
UNCOV
132
                FailureSourceIdx: index,
×
UNCOV
133
        }
×
UNCOV
134
}
×
135

136
// ErrorDecrypter is an interface that is used to decrypt the onion encrypted
137
// failure reason an extra out a well formed error.
138
type ErrorDecrypter interface {
139
        // DecryptError peels off each layer of onion encryption from the first
140
        // hop, to the source of the error. A fully populated
141
        // lnwire.FailureMessage is returned along with the source of the
142
        // error.
143
        DecryptError(lnwire.OpaqueReason) (*ForwardingError, error)
144
}
145

146
// UnknownEncrypterType is an error message used to signal that an unexpected
147
// EncrypterType was encountered during decoding.
148
type UnknownEncrypterType hop.EncrypterType
149

150
// Error returns a formatted error indicating the invalid EncrypterType.
151
func (e UnknownEncrypterType) Error() string {
×
152
        return fmt.Sprintf("unknown error encrypter type: %d", e)
×
153
}
×
154

155
// OnionErrorDecrypter is the interface that provides onion level error
156
// decryption.
157
type OnionErrorDecrypter interface {
158
        // DecryptError attempts to decrypt the passed encrypted error response.
159
        // The onion failure is encrypted in backward manner, starting from the
160
        // node where error have occurred. As a result, in order to decrypt the
161
        // error we need get all shared secret and apply decryption in the
162
        // reverse order.
163
        DecryptError(encryptedData []byte) (*sphinx.DecryptedError, error)
164
}
165

166
// SphinxErrorDecrypter wraps the sphinx data SphinxErrorDecrypter and maps the
167
// returned errors to concrete lnwire.FailureMessage instances.
168
type SphinxErrorDecrypter struct {
169
        OnionErrorDecrypter
170
}
171

172
// DecryptError peels off each layer of onion encryption from the first hop, to
173
// the source of the error. A fully populated lnwire.FailureMessage is returned
174
// along with the source of the error.
175
//
176
// NOTE: Part of the ErrorDecrypter interface.
177
func (s *SphinxErrorDecrypter) DecryptError(reason lnwire.OpaqueReason) (
178
        *ForwardingError, error) {
3✔
179

3✔
180
        failure, err := s.OnionErrorDecrypter.DecryptError(reason)
3✔
181
        if err != nil {
3✔
UNCOV
182
                return nil, err
×
UNCOV
183
        }
×
184

185
        // Decode the failure. If an error occurs, we leave the failure message
186
        // field nil.
187
        r := bytes.NewReader(failure.Message)
3✔
188
        failureMsg, err := lnwire.DecodeFailure(r, 0)
3✔
189
        if err != nil {
3✔
UNCOV
190
                return NewUnknownForwardingError(failure.SenderIdx), nil
×
UNCOV
191
        }
×
192

193
        return NewForwardingError(failureMsg, failure.SenderIdx), nil
3✔
194
}
195

196
// A compile time check to ensure ErrorDecrypter implements the Deobfuscator
197
// interface.
198
var _ ErrorDecrypter = (*SphinxErrorDecrypter)(nil)
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