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

lightningnetwork / lnd / 12312390362

13 Dec 2024 08:44AM UTC coverage: 57.458% (+8.5%) from 48.92%
12312390362

Pull #9343

github

ellemouton
fn: rework the ContextGuard and add tests

In this commit, the ContextGuard struct is re-worked such that the
context that its new main WithCtx method provides is cancelled in sync
with a parent context being cancelled or with it's quit channel being
cancelled. Tests are added to assert the behaviour. In order for the
close of the quit channel to be consistent with the cancelling of the
derived context, the quit channel _must_ be contained internal to the
ContextGuard so that callers are only able to close the channel via the
exposed Quit method which will then take care to first cancel any
derived context that depend on the quit channel before returning.
Pull Request #9343: fn: expand the ContextGuard and add tests

101853 of 177264 relevant lines covered (57.46%)

24972.93 hits per line

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

73.98
/htlcswitch/circuit.go
1
package htlcswitch
2

3
import (
4
        "encoding/binary"
5
        "io"
6

7
        "github.com/lightningnetwork/lnd/channeldb"
8
        "github.com/lightningnetwork/lnd/graph/db/models"
9
        "github.com/lightningnetwork/lnd/htlcswitch/hop"
10
        "github.com/lightningnetwork/lnd/lnwire"
11
)
12

13
// EmptyCircuitKey is a default value for an outgoing circuit key returned when
14
// a circuit's keystone has not been set. Note that this value is invalid for
15
// use as a keystone, since the outgoing channel id can never be equal to
16
// sourceHop.
17
var EmptyCircuitKey CircuitKey
18

19
// CircuitKey is a tuple of channel ID and HTLC ID, used to uniquely identify
20
// HTLCs in a circuit. Circuits are identified primarily by the circuit key of
21
// the incoming HTLC. However, a circuit may also be referenced by its outgoing
22
// circuit key after the HTLC has been forwarded via the outgoing link.
23
type CircuitKey = models.CircuitKey
24

25
// PaymentCircuit is used by the switch as placeholder between when the
26
// switch makes a forwarding decision and the outgoing link determines the
27
// proper HTLC ID for the local log. After the outgoing HTLC ID has been
28
// determined, the half circuit will be converted into a full PaymentCircuit.
29
type PaymentCircuit struct {
30
        // AddRef is the forward reference of the Add update in the incoming
31
        // link's forwarding package. This value is set on the htlcPacket of the
32
        // returned settle/fail so that it can be removed from disk.
33
        AddRef channeldb.AddRef
34

35
        // Incoming is the circuit key identifying the incoming channel and htlc
36
        // index from which this ADD originates.
37
        Incoming CircuitKey
38

39
        // Outgoing is the circuit key identifying the outgoing channel, and the
40
        // HTLC index that was used to forward the ADD. It will be nil if this
41
        // circuit's keystone has not been set.
42
        Outgoing *CircuitKey
43

44
        // PaymentHash used as unique identifier of payment.
45
        PaymentHash [32]byte
46

47
        // IncomingAmount is the value of the HTLC from the incoming link.
48
        IncomingAmount lnwire.MilliSatoshi
49

50
        // OutgoingAmount specifies the value of the HTLC leaving the switch,
51
        // either as a payment or forwarded amount.
52
        OutgoingAmount lnwire.MilliSatoshi
53

54
        // ErrorEncrypter is used to re-encrypt the onion failure before
55
        // sending it back to the originator of the payment.
56
        ErrorEncrypter hop.ErrorEncrypter
57

58
        // LoadedFromDisk is set true for any circuits loaded after the circuit
59
        // map is reloaded from disk.
60
        //
61
        // NOTE: This value is determined implicitly during a restart. It is not
62
        // persisted, and should never be set outside the circuit map.
63
        LoadedFromDisk bool
64
}
65

66
// HasKeystone returns true if an outgoing link has assigned this circuit's
67
// outgoing circuit key.
68
func (c *PaymentCircuit) HasKeystone() bool {
798✔
69
        return c.Outgoing != nil
798✔
70
}
798✔
71

72
// newPaymentCircuit initializes a payment circuit on the heap using the payment
73
// hash and an in-memory htlc packet.
74
func newPaymentCircuit(hash *[32]byte, pkt *htlcPacket) *PaymentCircuit {
498✔
75
        var addRef channeldb.AddRef
498✔
76
        if pkt.sourceRef != nil {
534✔
77
                addRef = *pkt.sourceRef
36✔
78
        }
36✔
79

80
        return &PaymentCircuit{
498✔
81
                AddRef: addRef,
498✔
82
                Incoming: CircuitKey{
498✔
83
                        ChanID: pkt.incomingChanID,
498✔
84
                        HtlcID: pkt.incomingHTLCID,
498✔
85
                },
498✔
86
                PaymentHash:    *hash,
498✔
87
                IncomingAmount: pkt.incomingAmount,
498✔
88
                OutgoingAmount: pkt.amount,
498✔
89
                ErrorEncrypter: pkt.obfuscator,
498✔
90
        }
498✔
91
}
92

93
// makePaymentCircuit initializes a payment circuit on the stack using the
94
// payment hash and an in-memory htlc packet.
95
func makePaymentCircuit(hash *[32]byte, pkt *htlcPacket) PaymentCircuit {
15✔
96
        var addRef channeldb.AddRef
15✔
97
        if pkt.sourceRef != nil {
15✔
98
                addRef = *pkt.sourceRef
×
99
        }
×
100

101
        return PaymentCircuit{
15✔
102
                AddRef: addRef,
15✔
103
                Incoming: CircuitKey{
15✔
104
                        ChanID: pkt.incomingChanID,
15✔
105
                        HtlcID: pkt.incomingHTLCID,
15✔
106
                },
15✔
107
                PaymentHash:    *hash,
15✔
108
                IncomingAmount: pkt.incomingAmount,
15✔
109
                OutgoingAmount: pkt.amount,
15✔
110
                ErrorEncrypter: pkt.obfuscator,
15✔
111
        }
15✔
112
}
113

114
// Encode writes a PaymentCircuit to the provided io.Writer.
115
func (c *PaymentCircuit) Encode(w io.Writer) error {
583✔
116
        if err := c.AddRef.Encode(w); err != nil {
583✔
117
                return err
×
118
        }
×
119

120
        if err := c.Incoming.Encode(w); err != nil {
583✔
121
                return err
×
122
        }
×
123

124
        if _, err := w.Write(c.PaymentHash[:]); err != nil {
583✔
125
                return err
×
126
        }
×
127

128
        var scratch [8]byte
583✔
129

583✔
130
        binary.BigEndian.PutUint64(scratch[:], uint64(c.IncomingAmount))
583✔
131
        if _, err := w.Write(scratch[:]); err != nil {
583✔
132
                return err
×
133
        }
×
134

135
        binary.BigEndian.PutUint64(scratch[:], uint64(c.OutgoingAmount))
583✔
136
        if _, err := w.Write(scratch[:]); err != nil {
583✔
137
                return err
×
138
        }
×
139

140
        // Defaults to EncrypterTypeNone.
141
        var encrypterType hop.EncrypterType
583✔
142
        if c.ErrorEncrypter != nil {
724✔
143
                encrypterType = c.ErrorEncrypter.Type()
141✔
144
        }
141✔
145

146
        err := binary.Write(w, binary.BigEndian, encrypterType)
583✔
147
        if err != nil {
583✔
148
                return err
×
149
        }
×
150

151
        // Skip encoding of error encrypter if this half add does not have one.
152
        if encrypterType == hop.EncrypterTypeNone {
1,025✔
153
                return nil
442✔
154
        }
442✔
155

156
        return c.ErrorEncrypter.Encode(w)
141✔
157
}
158

159
// Decode reads a PaymentCircuit from the provided io.Reader.
160
func (c *PaymentCircuit) Decode(r io.Reader) error {
102✔
161
        if err := c.AddRef.Decode(r); err != nil {
102✔
162
                return err
×
163
        }
×
164

165
        if err := c.Incoming.Decode(r); err != nil {
102✔
166
                return err
×
167
        }
×
168

169
        if _, err := io.ReadFull(r, c.PaymentHash[:]); err != nil {
102✔
170
                return err
×
171
        }
×
172

173
        var scratch [8]byte
102✔
174

102✔
175
        if _, err := io.ReadFull(r, scratch[:]); err != nil {
102✔
176
                return err
×
177
        }
×
178
        c.IncomingAmount = lnwire.MilliSatoshi(
102✔
179
                binary.BigEndian.Uint64(scratch[:]))
102✔
180

102✔
181
        if _, err := io.ReadFull(r, scratch[:]); err != nil {
102✔
182
                return err
×
183
        }
×
184
        c.OutgoingAmount = lnwire.MilliSatoshi(
102✔
185
                binary.BigEndian.Uint64(scratch[:]))
102✔
186

102✔
187
        // Read the encrypter type used for this circuit.
102✔
188
        var encrypterType hop.EncrypterType
102✔
189
        err := binary.Read(r, binary.BigEndian, &encrypterType)
102✔
190
        if err != nil {
102✔
191
                return err
×
192
        }
×
193

194
        switch encrypterType {
102✔
195
        case hop.EncrypterTypeNone:
4✔
196
                // No encrypter was provided, such as when the payment is
4✔
197
                // locally initiated.
4✔
198
                return nil
4✔
199

200
        case hop.EncrypterTypeSphinx:
32✔
201
                // Sphinx encrypter was used as this is a forwarded HTLC.
32✔
202
                c.ErrorEncrypter = hop.NewSphinxErrorEncrypter()
32✔
203

204
        case hop.EncrypterTypeMock:
66✔
205
                // Test encrypter.
66✔
206
                c.ErrorEncrypter = NewMockObfuscator()
66✔
207

208
        case hop.EncrypterTypeIntroduction:
×
209
                c.ErrorEncrypter = hop.NewIntroductionErrorEncrypter()
×
210

211
        case hop.EncrypterTypeRelaying:
×
212
                c.ErrorEncrypter = hop.NewRelayingErrorEncrypter()
×
213

214
        default:
×
215
                return UnknownEncrypterType(encrypterType)
×
216
        }
217

218
        return c.ErrorEncrypter.Decode(r)
98✔
219
}
220

221
// InKey returns the primary identifier for the circuit corresponding to the
222
// incoming HTLC.
223
func (c *PaymentCircuit) InKey() CircuitKey {
1,549✔
224
        return c.Incoming
1,549✔
225
}
1,549✔
226

227
// OutKey returns the keystone identifying the outgoing link and HTLC ID. If the
228
// circuit hasn't been completed, this method returns an EmptyKeystone, which is
229
// an invalid outgoing circuit key. Only call this method if HasKeystone returns
230
// true.
231
func (c *PaymentCircuit) OutKey() CircuitKey {
1,631✔
232
        if c.Outgoing != nil {
3,243✔
233
                return *c.Outgoing
1,612✔
234
        }
1,612✔
235

236
        return EmptyCircuitKey
19✔
237
}
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