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

lightningnetwork / lnd / 15561477203

10 Jun 2025 01:54PM UTC coverage: 58.351% (-10.1%) from 68.487%
15561477203

Pull #9356

github

web-flow
Merge 6440b25db into c6d6d4c0b
Pull Request #9356: lnrpc: add incoming/outgoing channel ids filter to forwarding history request

33 of 36 new or added lines in 2 files covered. (91.67%)

28366 existing lines in 455 files now uncovered.

97715 of 167461 relevant lines covered (58.35%)

1.81 hits per line

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

60.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 {
3✔
69
        return c.Outgoing != nil
3✔
70
}
3✔
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 {
3✔
75
        var addRef channeldb.AddRef
3✔
76
        if pkt.sourceRef != nil {
6✔
77
                addRef = *pkt.sourceRef
3✔
78
        }
3✔
79

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

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

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

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

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

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

128
        var scratch [8]byte
3✔
129

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

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

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

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

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

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

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

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

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

173
        var scratch [8]byte
3✔
174

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

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

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

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

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

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

208
        case hop.EncrypterTypeIntroduction:
3✔
209
                c.ErrorEncrypter = hop.NewIntroductionErrorEncrypter()
3✔
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)
3✔
219
}
220

221
// InKey returns the primary identifier for the circuit corresponding to the
222
// incoming HTLC.
223
func (c *PaymentCircuit) InKey() CircuitKey {
3✔
224
        return c.Incoming
3✔
225
}
3✔
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 {
3✔
232
        if c.Outgoing != nil {
6✔
233
                return *c.Outgoing
3✔
234
        }
3✔
235

UNCOV
236
        return EmptyCircuitKey
×
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