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

lightningnetwork / lnd / 13536249039

26 Feb 2025 03:42AM UTC coverage: 57.462% (-1.4%) from 58.835%
13536249039

Pull #8453

github

Roasbeef
peer: update chooseDeliveryScript to gen script if needed

In this commit, we update `chooseDeliveryScript` to generate a new
script if needed. This allows us to fold in a few other lines that
always followed this function into this expanded function.

The tests have been updated accordingly.
Pull Request #8453: [4/4] - multi: integrate new rbf coop close FSM into the existing peer flow

275 of 1318 new or added lines in 22 files covered. (20.86%)

19521 existing lines in 257 files now uncovered.

103858 of 180741 relevant lines covered (57.46%)

24750.23 hits per line

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

39.29
/htlcswitch/hop/error_encryptor.go
1
package hop
2

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

8
        "github.com/btcsuite/btcd/btcec/v2"
9
        sphinx "github.com/lightningnetwork/lightning-onion"
10
        "github.com/lightningnetwork/lnd/lnwire"
11
)
12

13
// EncrypterType establishes an enum used in serialization to indicate how to
14
// decode a concrete instance of the ErrorEncrypter interface.
15
type EncrypterType byte
16

17
const (
18
        // EncrypterTypeNone signals that no error encyrpter is present, this
19
        // can happen if the htlc is originates in the switch.
20
        EncrypterTypeNone EncrypterType = 0
21

22
        // EncrypterTypeSphinx is used to identify a sphinx onion error
23
        // encrypter instance.
24
        EncrypterTypeSphinx = 1
25

26
        // EncrypterTypeMock is used to identify a mock obfuscator instance.
27
        EncrypterTypeMock = 2
28

29
        // EncrypterTypeIntroduction is used to identify a sphinx onion error
30
        // encrypter where we are the introduction node in a blinded route. It
31
        // has the same functionality as EncrypterTypeSphinx, but is used to
32
        // mark our special-case error handling.
33
        EncrypterTypeIntroduction = 3
34

35
        // EncrypterTypeRelaying is used to identify a sphinx onion error
36
        // encryper where we are a relaying node in a blinded route. It has
37
        // the same functionality as a EncrypterTypeSphinx, but is used to mark
38
        // our special-case error handling.
39
        EncrypterTypeRelaying = 4
40
)
41

42
// IsBlinded returns a boolean indicating whether the error encrypter belongs
43
// to a blinded route.
44
func (e EncrypterType) IsBlinded() bool {
121✔
45
        return e == EncrypterTypeIntroduction || e == EncrypterTypeRelaying
121✔
46
}
121✔
47

48
// ErrorEncrypterExtracter defines a function signature that extracts an
49
// ErrorEncrypter from an sphinx OnionPacket.
50
type ErrorEncrypterExtracter func(*btcec.PublicKey) (ErrorEncrypter,
51
        lnwire.FailCode)
52

53
// ErrorEncrypter is an interface that is used to encrypt HTLC related errors
54
// at the source of the error, and also at each intermediate hop all the way
55
// back to the source of the payment.
56
type ErrorEncrypter interface {
57
        // EncryptFirstHop transforms a concrete failure message into an
58
        // encrypted opaque failure reason. This method will be used at the
59
        // source that the error occurs. It differs from IntermediateEncrypt
60
        // slightly, in that it computes a proper MAC over the error.
61
        EncryptFirstHop(lnwire.FailureMessage) (lnwire.OpaqueReason, error)
62

63
        // EncryptMalformedError is similar to EncryptFirstHop (it adds the
64
        // MAC), but it accepts an opaque failure reason rather than a failure
65
        // message. This method is used when we receive an
66
        // UpdateFailMalformedHTLC from the remote peer and then need to
67
        // convert that into a proper error from only the raw bytes.
68
        EncryptMalformedError(lnwire.OpaqueReason) lnwire.OpaqueReason
69

70
        // IntermediateEncrypt wraps an already encrypted opaque reason error
71
        // in an additional layer of onion encryption. This process repeats
72
        // until the error arrives at the source of the payment.
73
        IntermediateEncrypt(lnwire.OpaqueReason) lnwire.OpaqueReason
74

75
        // Type returns an enum indicating the underlying concrete instance
76
        // backing this interface.
77
        Type() EncrypterType
78

79
        // Encode serializes the encrypter's ephemeral public key to the given
80
        // io.Writer.
81
        Encode(io.Writer) error
82

83
        // Decode deserializes the encrypter' ephemeral public key from the
84
        // given io.Reader.
85
        Decode(io.Reader) error
86

87
        // Reextract rederives the encrypter using the extracter, performing an
88
        // ECDH with the sphinx router's key and the ephemeral public key.
89
        //
90
        // NOTE: This should be called shortly after Decode to properly
91
        // reinitialize the error encrypter.
92
        Reextract(ErrorEncrypterExtracter) error
93
}
94

95
// SphinxErrorEncrypter is a concrete implementation of both the ErrorEncrypter
96
// interface backed by an implementation of the Sphinx packet format. As a
97
// result, all errors handled are themselves wrapped in layers of onion
98
// encryption and must be treated as such accordingly.
99
type SphinxErrorEncrypter struct {
100
        *sphinx.OnionErrorEncrypter
101

102
        EphemeralKey *btcec.PublicKey
103
}
104

105
// NewSphinxErrorEncrypter initializes a blank sphinx error encrypter, that
106
// should be used to deserialize an encoded SphinxErrorEncrypter. Since the
107
// actual encrypter is not stored in plaintext while at rest, reconstructing the
108
// error encrypter requires:
109
//  1. Decode: to deserialize the ephemeral public key.
110
//  2. Reextract: to "unlock" the actual error encrypter using an active
111
//     OnionProcessor.
112
func NewSphinxErrorEncrypter() *SphinxErrorEncrypter {
32✔
113
        return &SphinxErrorEncrypter{
32✔
114
                OnionErrorEncrypter: nil,
32✔
115
                EphemeralKey:        &btcec.PublicKey{},
32✔
116
        }
32✔
117
}
32✔
118

119
// EncryptFirstHop transforms a concrete failure message into an encrypted
120
// opaque failure reason. This method will be used at the source that the error
121
// occurs. It differs from BackwardObfuscate slightly, in that it computes a
122
// proper MAC over the error.
123
//
124
// NOTE: Part of the ErrorEncrypter interface.
125
func (s *SphinxErrorEncrypter) EncryptFirstHop(
UNCOV
126
        failure lnwire.FailureMessage) (lnwire.OpaqueReason, error) {
×
UNCOV
127

×
UNCOV
128
        var b bytes.Buffer
×
UNCOV
129
        if err := lnwire.EncodeFailure(&b, failure, 0); err != nil {
×
130
                return nil, err
×
131
        }
×
132

133
        // We pass a true as the first parameter to indicate that a MAC should
134
        // be added.
UNCOV
135
        return s.EncryptError(true, b.Bytes()), nil
×
136
}
137

138
// EncryptMalformedError is similar to EncryptFirstHop (it adds the MAC), but
139
// it accepts an opaque failure reason rather than a failure message. This
140
// method is used when we receive an UpdateFailMalformedHTLC from the remote
141
// peer and then need to convert that into an proper error from only the raw
142
// bytes.
143
//
144
// NOTE: Part of the ErrorEncrypter interface.
145
func (s *SphinxErrorEncrypter) EncryptMalformedError(
UNCOV
146
        reason lnwire.OpaqueReason) lnwire.OpaqueReason {
×
UNCOV
147

×
UNCOV
148
        return s.EncryptError(true, reason)
×
UNCOV
149
}
×
150

151
// IntermediateEncrypt wraps an already encrypted opaque reason error in an
152
// additional layer of onion encryption. This process repeats until the error
153
// arrives at the source of the payment. We re-encrypt the message on the
154
// backwards path to ensure that the error is indistinguishable from any other
155
// error seen.
156
//
157
// NOTE: Part of the ErrorEncrypter interface.
158
func (s *SphinxErrorEncrypter) IntermediateEncrypt(
UNCOV
159
        reason lnwire.OpaqueReason) lnwire.OpaqueReason {
×
UNCOV
160

×
UNCOV
161
        return s.EncryptError(false, reason)
×
UNCOV
162
}
×
163

164
// Type returns the identifier for a sphinx error encrypter.
165
func (s *SphinxErrorEncrypter) Type() EncrypterType {
28✔
166
        return EncrypterTypeSphinx
28✔
167
}
28✔
168

169
// Encode serializes the error encrypter' ephemeral public key to the provided
170
// io.Writer.
171
func (s *SphinxErrorEncrypter) Encode(w io.Writer) error {
28✔
172
        ephemeral := s.EphemeralKey.SerializeCompressed()
28✔
173
        _, err := w.Write(ephemeral)
28✔
174
        return err
28✔
175
}
28✔
176

177
// Decode reconstructs the error encrypter's ephemeral public key from the
178
// provided io.Reader.
179
func (s *SphinxErrorEncrypter) Decode(r io.Reader) error {
32✔
180
        var ephemeral [33]byte
32✔
181
        if _, err := io.ReadFull(r, ephemeral[:]); err != nil {
32✔
182
                return err
×
183
        }
×
184

185
        var err error
32✔
186
        s.EphemeralKey, err = btcec.ParsePubKey(ephemeral[:])
32✔
187
        if err != nil {
32✔
188
                return err
×
189
        }
×
190

191
        return nil
32✔
192
}
193

194
// Reextract rederives the error encrypter from the currently held EphemeralKey.
195
// This intended to be used shortly after Decode, to fully initialize a
196
// SphinxErrorEncrypter.
197
func (s *SphinxErrorEncrypter) Reextract(
198
        extract ErrorEncrypterExtracter) error {
32✔
199

32✔
200
        obfuscator, failcode := extract(s.EphemeralKey)
32✔
201
        if failcode != lnwire.CodeNone {
32✔
202
                // This should never happen, since we already validated that
×
203
                // this obfuscator can be extracted when it was received in the
×
204
                // link.
×
205
                return fmt.Errorf("unable to reconstruct onion "+
×
206
                        "obfuscator, got failcode: %d", failcode)
×
207
        }
×
208

209
        sphinxEncrypter, ok := obfuscator.(*SphinxErrorEncrypter)
32✔
210
        if !ok {
32✔
211
                return fmt.Errorf("incorrect onion error extracter")
×
212
        }
×
213

214
        // Copy the freshly extracted encrypter.
215
        s.OnionErrorEncrypter = sphinxEncrypter.OnionErrorEncrypter
32✔
216

32✔
217
        return nil
32✔
218
}
219

220
// A compile time check to ensure SphinxErrorEncrypter implements the
221
// ErrorEncrypter interface.
222
var _ ErrorEncrypter = (*SphinxErrorEncrypter)(nil)
223

224
// A compile time check to ensure that IntroductionErrorEncrypter implements
225
// the ErrorEncrypter interface.
226
var _ ErrorEncrypter = (*IntroductionErrorEncrypter)(nil)
227

228
// IntroductionErrorEncrypter is a wrapper type on SphinxErrorEncrypter which
229
// is used to signal that we have special HTLC error handling for this hop.
230
type IntroductionErrorEncrypter struct {
231
        // ErrorEncrypter is the underlying error encrypter, embedded
232
        // directly in the struct so that we don't have to re-implement the
233
        // ErrorEncrypter interface.
234
        ErrorEncrypter
235
}
236

237
// NewIntroductionErrorEncrypter returns a blank IntroductionErrorEncrypter.
UNCOV
238
func NewIntroductionErrorEncrypter() *IntroductionErrorEncrypter {
×
UNCOV
239
        return &IntroductionErrorEncrypter{
×
UNCOV
240
                ErrorEncrypter: NewSphinxErrorEncrypter(),
×
UNCOV
241
        }
×
UNCOV
242
}
×
243

244
// Type returns the identifier for an introduction error encrypter.
UNCOV
245
func (i *IntroductionErrorEncrypter) Type() EncrypterType {
×
UNCOV
246
        return EncrypterTypeIntroduction
×
UNCOV
247
}
×
248

249
// Reextract rederives the error encrypter from the currently held EphemeralKey,
250
// relying on the logic in the underlying SphinxErrorEncrypter.
251
func (i *IntroductionErrorEncrypter) Reextract(
UNCOV
252
        extract ErrorEncrypterExtracter) error {
×
UNCOV
253

×
UNCOV
254
        return i.ErrorEncrypter.Reextract(extract)
×
UNCOV
255
}
×
256

257
// A compile time check to ensure that RelayingErrorEncrypte implements
258
// the ErrorEncrypter interface.
259
var _ ErrorEncrypter = (*RelayingErrorEncrypter)(nil)
260

261
// RelayingErrorEncrypter is a wrapper type on SphinxErrorEncrypter which
262
// is used to signal that we have special HTLC error handling for this hop.
263
type RelayingErrorEncrypter struct {
264
        ErrorEncrypter
265
}
266

267
// NewRelayingErrorEncrypter returns a blank RelayingErrorEncrypter with
268
// an underlying SphinxErrorEncrypter.
269
func NewRelayingErrorEncrypter() *RelayingErrorEncrypter {
×
270
        return &RelayingErrorEncrypter{
×
271
                ErrorEncrypter: NewSphinxErrorEncrypter(),
×
272
        }
×
273
}
×
274

275
// Type returns the identifier for a relaying error encrypter.
UNCOV
276
func (r *RelayingErrorEncrypter) Type() EncrypterType {
×
UNCOV
277
        return EncrypterTypeRelaying
×
UNCOV
278
}
×
279

280
// Reextract rederives the error encrypter from the currently held EphemeralKey,
281
// relying on the logic in the underlying SphinxErrorEncrypter.
282
func (r *RelayingErrorEncrypter) Reextract(
283
        extract ErrorEncrypterExtracter) error {
×
284

×
285
        return r.ErrorEncrypter.Reextract(extract)
×
286
}
×
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