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

lightningnetwork / lnd / 13566028875

27 Feb 2025 12:09PM UTC coverage: 49.396% (-9.4%) from 58.748%
13566028875

Pull #9555

github

ellemouton
graph/db: populate the graph cache in Start instead of during construction

In this commit, we move the graph cache population logic out of the
ChannelGraph constructor and into its Start method instead.
Pull Request #9555: graph: extract cache from CRUD [6]

34 of 54 new or added lines in 4 files covered. (62.96%)

27464 existing lines in 436 files now uncovered.

101095 of 204664 relevant lines covered (49.4%)

1.54 hits per line

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

73.81
/channeldb/payment_status.go
1
package channeldb
2

3
import "fmt"
4

5
// PaymentStatus represent current status of payment.
6
type PaymentStatus byte
7

8
const (
9
        // NOTE: PaymentStatus = 0 was previously used for status unknown and
10
        // is now deprecated.
11

12
        // StatusInitiated is the status where a payment has just been
13
        // initiated.
14
        StatusInitiated PaymentStatus = 1
15

16
        // StatusInFlight is the status where a payment has been initiated, but
17
        // a response has not been received.
18
        StatusInFlight PaymentStatus = 2
19

20
        // StatusSucceeded is the status where a payment has been initiated and
21
        // the payment was completed successfully.
22
        StatusSucceeded PaymentStatus = 3
23

24
        // StatusFailed is the status where a payment has been initiated and a
25
        // failure result has come back.
26
        StatusFailed PaymentStatus = 4
27
)
28

29
// errPaymentStatusUnknown is returned when a payment has an unknown status.
30
var errPaymentStatusUnknown = fmt.Errorf("unknown payment status")
31

32
// String returns readable representation of payment status.
33
func (ps PaymentStatus) String() string {
3✔
34
        switch ps {
3✔
35
        case StatusInitiated:
3✔
36
                return "Initiated"
3✔
37

38
        case StatusInFlight:
3✔
39
                return "In Flight"
3✔
40

41
        case StatusSucceeded:
3✔
42
                return "Succeeded"
3✔
43

44
        case StatusFailed:
3✔
45
                return "Failed"
3✔
46

UNCOV
47
        default:
×
UNCOV
48
                return "Unknown"
×
49
        }
50
}
51

52
// initializable returns an error to specify whether initiating the payment
53
// with its current status is allowed. A payment can only be initialized if it
54
// hasn't been created yet or already failed.
55
func (ps PaymentStatus) initializable() error {
3✔
56
        switch ps {
3✔
57
        // The payment has been created already. We will disallow creating it
58
        // again in case other goroutines have already been creating HTLCs for
59
        // it.
UNCOV
60
        case StatusInitiated:
×
UNCOV
61
                return ErrPaymentExists
×
62

63
        // We already have an InFlight payment on the network. We will disallow
64
        // any new payments.
65
        case StatusInFlight:
3✔
66
                return ErrPaymentInFlight
3✔
67

68
        // The payment has been attempted and is succeeded so we won't allow
69
        // creating it again.
UNCOV
70
        case StatusSucceeded:
×
UNCOV
71
                return ErrAlreadyPaid
×
72

73
        // We allow retrying failed payments.
74
        case StatusFailed:
3✔
75
                return nil
3✔
76

UNCOV
77
        default:
×
UNCOV
78
                return fmt.Errorf("%w: %v", ErrUnknownPaymentStatus, ps)
×
79
        }
80
}
81

82
// removable returns an error to specify whether deleting the payment with its
83
// current status is allowed. A payment cannot be safely deleted if it has
84
// inflight HTLCs.
85
func (ps PaymentStatus) removable() error {
3✔
86
        switch ps {
3✔
87
        // The payment has been created but has no HTLCs and can be removed.
UNCOV
88
        case StatusInitiated:
×
UNCOV
89
                return nil
×
90

91
        // There are still inflight HTLCs and the payment needs to wait for the
92
        // final outcomes.
UNCOV
93
        case StatusInFlight:
×
UNCOV
94
                return ErrPaymentInFlight
×
95

96
        // The payment has been attempted and is succeeded and is allowed to be
97
        // removed.
98
        case StatusSucceeded:
3✔
99
                return nil
3✔
100

101
        // Failed payments are allowed to be removed.
UNCOV
102
        case StatusFailed:
×
UNCOV
103
                return nil
×
104

UNCOV
105
        default:
×
UNCOV
106
                return fmt.Errorf("%w: %v", ErrUnknownPaymentStatus, ps)
×
107
        }
108
}
109

110
// updatable returns an error to specify whether the payment's HTLCs can be
111
// updated. A payment can update its HTLCs when it has inflight HTLCs.
112
func (ps PaymentStatus) updatable() error {
3✔
113
        switch ps {
3✔
114
        // Newly created payments can be updated.
115
        case StatusInitiated:
3✔
116
                return nil
3✔
117

118
        // Inflight payments can be updated.
119
        case StatusInFlight:
3✔
120
                return nil
3✔
121

122
        // If the payment has a terminal condition, we won't allow any updates.
123
        case StatusSucceeded:
3✔
124
                return ErrPaymentAlreadySucceeded
3✔
125

126
        case StatusFailed:
3✔
127
                return ErrPaymentAlreadyFailed
3✔
128

UNCOV
129
        default:
×
UNCOV
130
                return fmt.Errorf("%w: %v", ErrUnknownPaymentStatus, ps)
×
131
        }
132
}
133

134
// decidePaymentStatus uses the payment's DB state to determine a memory status
135
// that's used by the payment router to decide following actions.
136
// Together, we use four variables to determine the payment's status,
137
//   - inflight: whether there are any pending HTLCs.
138
//   - settled: whether any of the HTLCs has been settled.
139
//   - htlc failed: whether any of the HTLCs has been failed.
140
//   - payment failed: whether the payment has been marked as failed.
141
//
142
// Based on the above variables, we derive the status using the following
143
// table,
144
// | inflight | settled | htlc failed | payment failed |         status       |
145
// |:--------:|:-------:|:-----------:|:--------------:|:--------------------:|
146
// |   true   |   true  |     true    |      true      |    StatusInFlight    |
147
// |   true   |   true  |     true    |      false     |    StatusInFlight    |
148
// |   true   |   true  |     false   |      true      |    StatusInFlight    |
149
// |   true   |   true  |     false   |      false     |    StatusInFlight    |
150
// |   true   |   false |     true    |      true      |    StatusInFlight    |
151
// |   true   |   false |     true    |      false     |    StatusInFlight    |
152
// |   true   |   false |     false   |      true      |    StatusInFlight    |
153
// |   true   |   false |     false   |      false     |    StatusInFlight    |
154
// |   false  |   true  |     true    |      true      |    StatusSucceeded   |
155
// |   false  |   true  |     true    |      false     |    StatusSucceeded   |
156
// |   false  |   true  |     false   |      true      |    StatusSucceeded   |
157
// |   false  |   true  |     false   |      false     |    StatusSucceeded   |
158
// |   false  |   false |     true    |      true      |      StatusFailed    |
159
// |   false  |   false |     true    |      false     |    StatusInFlight    |
160
// |   false  |   false |     false   |      true      |      StatusFailed    |
161
// |   false  |   false |     false   |      false     |    StatusInitiated   |
162
//
163
// When `inflight`, `settled`, `htlc failed`, and `payment failed` are false,
164
// this indicates the payment is newly created and hasn't made any HTLCs yet.
165
// When `inflight` and `settled` are false, `htlc failed` is true yet `payment
166
// failed` is false, this indicates all the payment's HTLCs have occurred a
167
// temporarily failure and the payment is still in-flight.
168
func decidePaymentStatus(htlcs []HTLCAttempt,
169
        reason *FailureReason) (PaymentStatus, error) {
3✔
170

3✔
171
        var (
3✔
172
                inflight      bool
3✔
173
                htlcSettled   bool
3✔
174
                htlcFailed    bool
3✔
175
                paymentFailed bool
3✔
176
        )
3✔
177

3✔
178
        // If we have a failure reason, the payment is failed.
3✔
179
        if reason != nil {
6✔
180
                paymentFailed = true
3✔
181
        }
3✔
182

183
        // Go through all HTLCs for this payment, check whether we have any
184
        // settled HTLC, and any still in-flight.
185
        for _, h := range htlcs {
6✔
186
                if h.Failure != nil {
6✔
187
                        htlcFailed = true
3✔
188
                        continue
3✔
189
                }
190

191
                if h.Settle != nil {
6✔
192
                        htlcSettled = true
3✔
193
                        continue
3✔
194
                }
195

196
                // If any of the HTLCs are not failed nor settled, we
197
                // still have inflight HTLCs.
198
                inflight = true
3✔
199
        }
200

201
        // Use the DB state to determine the status of the payment.
202
        switch {
3✔
203
        // If we have inflight HTLCs, no matter we have settled or failed
204
        // HTLCs, or the payment failed, we still consider it inflight so we
205
        // inform upper systems to wait for the results.
206
        case inflight:
3✔
207
                return StatusInFlight, nil
3✔
208

209
        // If we have no in-flight HTLCs, and at least one of the HTLCs is
210
        // settled, the payment succeeded.
211
        //
212
        // NOTE: when reaching this case, paymentFailed could be true, which
213
        // means we have a conflicting state for this payment. We choose to
214
        // mark the payment as succeeded because it's the receiver's
215
        // responsibility to only settle the payment iff all HTLCs are
216
        // received.
217
        case htlcSettled:
3✔
218
                return StatusSucceeded, nil
3✔
219

220
        // If we have no in-flight HTLCs, and the payment failure is set, the
221
        // payment is considered failed.
222
        //
223
        // NOTE: when reaching this case, settled must be false.
224
        case paymentFailed:
3✔
225
                return StatusFailed, nil
3✔
226

227
        // If we have no in-flight HTLCs, yet the payment is NOT failed, it
228
        // means all the HTLCs are failed. In this case we can attempt more
229
        // HTLCs.
230
        //
231
        // NOTE: when reaching this case, both settled and paymentFailed must
232
        // be false.
233
        case htlcFailed:
3✔
234
                return StatusInFlight, nil
3✔
235

236
        // If none of the HTLCs is either settled or failed, and we have no
237
        // inflight HTLCs, this means the payment has no HTLCs created yet.
238
        //
239
        // NOTE: when reaching this case, both settled and paymentFailed must
240
        // be false.
241
        case !htlcFailed:
3✔
242
                return StatusInitiated, nil
3✔
243

244
        // Otherwise an impossible state is reached.
245
        //
246
        // NOTE: we should never end up here.
247
        default:
×
248
                log.Error("Impossible payment state reached")
×
249
                return 0, fmt.Errorf("%w: payment is corrupted",
×
250
                        errPaymentStatusUnknown)
×
251
        }
252
}
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