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

lightningnetwork / lnd / 11216766535

07 Oct 2024 01:37PM UTC coverage: 57.817% (-1.0%) from 58.817%
11216766535

Pull #9148

github

ProofOfKeags
lnwire: remove kickoff feerate from propose/commit
Pull Request #9148: DynComms [2/n]: lnwire: add authenticated wire messages for Dyn*

571 of 879 new or added lines in 16 files covered. (64.96%)

23253 existing lines in 251 files now uncovered.

99022 of 171268 relevant lines covered (57.82%)

38420.67 hits per line

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

73.24
/htlcswitch/quiescer.go
1
//nolint:unused
2
package htlcswitch
3

4
import (
5
        "fmt"
6

7
        "github.com/lightningnetwork/lnd/fn"
8
        "github.com/lightningnetwork/lnd/lntypes"
9
        "github.com/lightningnetwork/lnd/lnwire"
10
)
11

12
var (
13
        // ErrStfuAlreadySent indicates that this channel has already sent an
14
        // Stfu message for this negotiation.
15
        ErrStfuAlreadySent = fmt.Errorf("stfu already sent")
16

17
        // ErrStfuAlreadyRcvd indicates that this channel has already received
18
        // an Stfu message for this negotiation.
19
        ErrStfuAlreadyRcvd = fmt.Errorf("stfu already received")
20

21
        // ErrNoQuiescenceInitiator indicates that the caller has requested the
22
        // quiescence initiator for a channel that is not yet quiescent.
23
        ErrNoQuiescenceInitiator = fmt.Errorf(
24
                "indeterminate quiescence initiator: channel is not quiescent",
25
        )
26

27
        // ErrPendingRemoteUpdates indicates that we have received an Stfu while
28
        // the remote party has issued updates that are not yet bilaterally
29
        // committed.
30
        ErrPendingRemoteUpdates = fmt.Errorf(
31
                "stfu received with pending remote updates",
32
        )
33

34
        // ErrPendingLocalUpdates indicates that we are attempting to send an
35
        // Stfu while we have issued updates that are not yet bilaterally
36
        // committed.
37
        ErrPendingLocalUpdates = fmt.Errorf(
38
                "stfu send attempted with pending local updates",
39
        )
40
)
41

42
type StfuReq = fn.Req[fn.Unit, fn.Result[lntypes.ChannelParty]]
43

44
type quiescer interface {
45
        // isQuiescent returns true if the state machine has been driven all the
46
        // way to completion. If this returns true, processes that depend on
47
        // channel quiescence may proceed.
48
        isQuiescent() bool
49

50
        // initStfu instructs the quiescer that we intend to begin a quiescence
51
        // negotiation where we are the initiator. We don't yet send stfu yet
52
        // because we need to wait for the link to give us a valid opportunity
53
        // to do so.
54
        initStfu(req StfuReq)
55

56
        // recvStfu is called when we receive an Stfu message from the remote.
57
        recvStfu(stfu lnwire.Stfu) error
58

59
        // canRecvUpdates returns true if we haven't yet received an Stfu which
60
        // would mark the end of the remote's ability to send updates.
61
        canRecvUpdates() bool
62

63
        // canSendUpdates returns true if we haven't yet sent an Stfu which
64
        // would mark the end of our ability to send updates.
65
        canSendUpdates() bool
66

67
        // drive drives the quiescence machine forward. It returns an error if
68
        // the state machine is in an invalid state.
69
        drive() error
70

71
        // onResume accepts a no return closure that will run when the quiescer
72
        // is resumed.
73
        onResume(hook func())
74

75
        // resume runs all of the deferred actions that have accumulated while
76
        // the channel has been quiescent and then resets the quiescer state to
77
        // its initial state.
78
        resume()
79
}
80

81
type quiescerCfg struct {
82
        // chanID marks what channel we are managing the state machine for. This
83
        // is important because the quiescer is responsible for constructing the
84
        // messages we send out and the ChannelID is a key field in that
85
        // message.
86
        chanID lnwire.ChannelID
87

88
        // channelInitiator indicates which ChannelParty originally opened the
89
        // channel. This is used to break ties when both sides of the channel
90
        // send Stfu claiming to be the initiator.
91
        channelInitiator lntypes.ChannelParty
92

93
        // numPendingUpdates is a function that returns the number of pending
94
        // originated by the party in the first argument that have yet to be
95
        // committed to the commitment transaction held by the party in the
96
        // second argument.
97
        numPendingUpdates func(lntypes.ChannelParty,
98
                lntypes.ChannelParty) uint64
99

100
        // sendMsg is a function that can be used to send an Stfu message over
101
        // the wire.
102
        sendMsg func(lnwire.Stfu) error
103
}
104

105
// quiescerLive is a state machine that tracks progression through the
106
// quiescence protocol.
107
type quiescerLive struct {
108
        cfg quiescerCfg
109

110
        // localInit indicates whether our path through this state machine was
111
        // initiated by our node. This can be true or false independently of
112
        // remoteInit.
113
        localInit bool
114

115
        // remoteInit indicates whether we received Stfu from our peer where the
116
        // message indicated that the remote node believes it was the initiator.
117
        // This can be true or false independently of localInit.
118
        remoteInit bool
119

120
        // sent tracks whether or not we have emitted Stfu for sending.
121
        sent bool
122

123
        // received tracks whether or not we have received Stfu from our peer.
124
        received bool
125

126
        // activeQuiescenceRequest is a possibly None Request that we should
127
        // resolve when we complete quiescence.
128
        activeQuiescenceReq fn.Option[StfuReq]
129

130
        // resumeQueue is a slice of hooks that will be called when the quiescer
131
        // is resumed. These are actions that needed to be deferred while the
132
        // channel was quiescent.
133
        resumeQueue []func()
134
}
135

136
// newQuiescer creates a new quiescer for the given channel.
137
func newQuiescer(cfg quiescerCfg) quiescer {
221✔
138
        return &quiescerLive{
221✔
139
                cfg: cfg,
221✔
140
        }
221✔
141
}
221✔
142

143
// recvStfu is called when we receive an Stfu message from the remote.
144
func (q *quiescerLive) recvStfu(msg lnwire.Stfu) error {
9✔
145
        // At the time of this writing, this check that we have already received
9✔
146
        // an Stfu is not strictly necessary, according to the specification.
9✔
147
        // However, it is fishy if we do and it is unclear how we should handle
9✔
148
        // such a case so we will err on the side of caution.
9✔
149
        if q.received {
10✔
150
                return fmt.Errorf("%w for channel %v", ErrStfuAlreadyRcvd,
1✔
151
                        q.cfg.chanID)
1✔
152
        }
1✔
153

154
        if !q.canRecvStfu() {
9✔
155
                return fmt.Errorf("%w for channel %v", ErrPendingRemoteUpdates,
1✔
156
                        q.cfg.chanID)
1✔
157
        }
1✔
158

159
        q.received = true
7✔
160

7✔
161
        // If the remote party sets the initiator bit to true then we will
7✔
162
        // remember that they are making a claim to the initiator role. This
7✔
163
        // does not necessarily mean they will get it, though.
7✔
164
        q.remoteInit = msg.Initiator
7✔
165

7✔
166
        // Since we just received an Stfu, we may have a newly quiesced state.
7✔
167
        // If so, we will try to resolve any outstanding StfuReqs.
7✔
168
        q.tryResolveStfuReq()
7✔
169

7✔
170
        return nil
7✔
171
}
172

173
// makeStfu is called when we are ready to send an Stfu message. It returns the
174
// Stfu message to be sent.
175
func (q *quiescerLive) makeStfu() fn.Result[lnwire.Stfu] {
6✔
176
        if q.sent {
6✔
NEW
177
                return fn.Errf[lnwire.Stfu]("%w for channel %v",
×
NEW
178
                        ErrStfuAlreadySent, q.cfg.chanID)
×
NEW
179
        }
×
180

181
        if !q.canSendStfu() {
6✔
NEW
182
                return fn.Errf[lnwire.Stfu]("%w for channel %v",
×
NEW
183
                        ErrPendingLocalUpdates, q.cfg.chanID)
×
NEW
184
        }
×
185

186
        stfu := lnwire.Stfu{
6✔
187
                ChanID:    q.cfg.chanID,
6✔
188
                Initiator: q.localInit,
6✔
189
        }
6✔
190

6✔
191
        return fn.Ok(stfu)
6✔
192
}
193

194
// oweStfu returns true if we owe the other party an Stfu. We owe the remote an
195
// Stfu when we have received but not yet sent an Stfu, or we are the initiator
196
// but have not yet sent an Stfu.
197
func (q *quiescerLive) oweStfu() bool {
2,598✔
198
        return (q.received || q.localInit) && !q.sent
2,598✔
199
}
2,598✔
200

201
// needStfu returns true if the remote owes us an Stfu. They owe us an Stfu when
202
// we have sent but not yet received an Stfu.
NEW
203
func (q *quiescerLive) needStfu() bool {
×
NEW
204
        return q.sent && !q.received
×
NEW
205
}
×
206

207
// isQuiescent returns true if the state machine has been driven all the way to
208
// completion. If this returns true, processes that depend on channel quiescence
209
// may proceed.
210
func (q *quiescerLive) isQuiescent() bool {
11✔
211
        return q.sent && q.received
11✔
212
}
11✔
213

214
// quiescenceInitiator determines which ChannelParty is the initiator of
215
// quiescence for the purposes of downstream protocols. If the channel is not
216
// currently quiescent, this method will return ErrNoDownstreamLeader.
217
func (q *quiescerLive) quiescenceInitiator() fn.Result[lntypes.ChannelParty] {
3✔
218
        switch {
3✔
NEW
219
        case !q.isQuiescent():
×
NEW
220
                return fn.Err[lntypes.ChannelParty](ErrNoQuiescenceInitiator)
×
221

222
        case q.localInit && q.remoteInit:
2✔
223
                // In the case of a tie, the channel initiator wins.
2✔
224
                return fn.Ok(q.cfg.channelInitiator)
2✔
225

NEW
226
        case !q.localInit && !q.remoteInit:
×
NEW
227
                // We assume it is impossible for both to be false if the
×
NEW
228
                // channel is quiescent.
×
NEW
229
                panic("impossible: one party must have initiated quiescence")
×
230

231
        case q.localInit:
1✔
232
                return fn.Ok(lntypes.Local)
1✔
233

NEW
234
        case q.remoteInit:
×
NEW
235
                return fn.Ok(lntypes.Remote)
×
236
        }
237

NEW
238
        panic("impossible: non-exhaustive switch quiescer.downstreamLeader")
×
239
}
240

241
// canSendUpdates returns true if we haven't yet sent an Stfu which would mark
242
// the end of our ability to send updates.
243
func (q *quiescerLive) canSendUpdates() bool {
5,756✔
244
        return !q.sent && !q.localInit
5,756✔
245
}
5,756✔
246

247
// canRecvUpdates returns true if we haven't yet received an Stfu which would
248
// mark the end of the remote's ability to send updates.
249
func (q *quiescerLive) canRecvUpdates() bool {
3,839✔
250
        return !q.received
3,839✔
251
}
3,839✔
252

253
// canSendStfu returns true if we can send an Stfu.
254
func (q *quiescerLive) canSendStfu() bool {
14✔
255
        return q.cfg.numPendingUpdates(lntypes.Local, lntypes.Local) == 0 &&
14✔
256
                q.cfg.numPendingUpdates(lntypes.Local, lntypes.Remote) == 0
14✔
257
}
14✔
258

259
// canRecvStfu returns true if we can receive an Stfu.
260
func (q *quiescerLive) canRecvStfu() bool {
8✔
261
        return q.cfg.numPendingUpdates(lntypes.Remote, lntypes.Local) == 0 &&
8✔
262
                q.cfg.numPendingUpdates(lntypes.Remote, lntypes.Remote) == 0
8✔
263
}
8✔
264

265
// drive drives the quiescence machine forward. It returns an error if the state
266
// machine is in an invalid state.
267
func (q *quiescerLive) drive() error {
2,598✔
268
        if !q.oweStfu() || !q.canSendStfu() {
5,190✔
269
                return nil
2,592✔
270
        }
2,592✔
271

272
        stfu, err := q.makeStfu().Unpack()
6✔
273
        if err != nil {
6✔
NEW
274
                return err
×
NEW
275
        }
×
276

277
        err = q.cfg.sendMsg(stfu)
6✔
278
        if err != nil {
6✔
NEW
279
                return err
×
NEW
280
        }
×
281

282
        q.sent = true
6✔
283

6✔
284
        // Since we just sent an Stfu, we may have a newly quiesced state.
6✔
285
        // If so, we will try to resolve any outstanding StfuReqs.
6✔
286
        q.tryResolveStfuReq()
6✔
287

6✔
288
        return nil
6✔
289
}
290

291
// tryResolveStfuReq attempts to resolve the active quiescence request if the
292
// state machine has reached a quiescent state.
293
func (q *quiescerLive) tryResolveStfuReq() {
13✔
294
        q.activeQuiescenceReq.WhenSome(
13✔
295
                func(req StfuReq) {
19✔
296
                        if q.isQuiescent() {
9✔
297
                                req.Resolve(q.quiescenceInitiator())
3✔
298
                                q.activeQuiescenceReq = fn.None[StfuReq]()
3✔
299
                        }
3✔
300
                },
301
        )
302
}
303

304
// initStfu instructs the quiescer that we intend to begin a quiescence
305
// negotiation where we are the initiator. We don't yet send stfu yet because
306
// we need to wait for the link to give us a valid opportunity to do so.
307
func (q *quiescerLive) initStfu(req StfuReq) {
3✔
308
        if q.localInit {
3✔
NEW
309
                req.Resolve(fn.Errf[lntypes.ChannelParty](
×
NEW
310
                        "quiescence already requested",
×
NEW
311
                ))
×
NEW
312

×
NEW
313
                return
×
NEW
314
        }
×
315

316
        q.localInit = true
3✔
317
        q.activeQuiescenceReq = fn.Some(req)
3✔
318
}
319

320
// onResume accepts a no return closure that will run when the quiescer is
321
// resumed.
322
func (q *quiescerLive) onResume(hook func()) {
2✔
323
        q.resumeQueue = append(q.resumeQueue, hook)
2✔
324
}
2✔
325

326
// resume runs all of the deferred actions that have accumulated while the
327
// channel has been quiescent and then resets the quiescer state to its initial
328
// state.
329
func (q *quiescerLive) resume() {
1✔
330
        for _, hook := range q.resumeQueue {
2✔
331
                hook()
1✔
332
        }
1✔
333
        q.localInit = false
1✔
334
        q.remoteInit = false
1✔
335
        q.sent = false
1✔
336
        q.received = false
1✔
337
        q.resumeQueue = nil
1✔
338
}
339

340
type quiescerNoop struct{}
341

342
var _ quiescer = (*quiescerNoop)(nil)
343

NEW
344
func (q *quiescerNoop) initStfu(req StfuReq) {
×
NEW
345
        req.Resolve(fn.Errf[lntypes.ChannelParty]("quiescence not supported"))
×
NEW
346
}
×
NEW
347
func (q *quiescerNoop) recvStfu(_ lnwire.Stfu) error { return nil }
×
NEW
348
func (q *quiescerNoop) canRecvUpdates() bool         { return true }
×
NEW
349
func (q *quiescerNoop) canSendUpdates() bool         { return true }
×
NEW
350
func (q *quiescerNoop) drive() error                 { return nil }
×
NEW
351
func (q *quiescerNoop) isQuiescent() bool            { return false }
×
NEW
352
func (q *quiescerNoop) onResume(hook func())         { hook() }
×
NEW
353
func (q *quiescerNoop) resume()                      {}
×
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