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

lightningnetwork / lnd / 11935436518

20 Nov 2024 02:29PM UTC coverage: 58.976% (+0.03%) from 58.951%
11935436518

push

github

web-flow
Merge pull request #9288 from lightningnetwork/channel-acceptor-commitment-type

[custom channels]: add taproot overlay channel type to channel acceptor

0 of 8 new or added lines in 1 file covered. (0.0%)

43 existing lines in 9 files now uncovered.

132813 of 225199 relevant lines covered (58.98%)

19538.34 hits per line

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

82.99
/chanacceptor/rpcacceptor.go
1
package chanacceptor
2

3
import (
4
        "encoding/hex"
5
        "errors"
6
        "fmt"
7
        "sync"
8
        "time"
9

10
        "github.com/btcsuite/btcd/btcutil"
11
        "github.com/btcsuite/btcd/chaincfg"
12
        "github.com/lightningnetwork/lnd/input"
13
        "github.com/lightningnetwork/lnd/lnrpc"
14
        "github.com/lightningnetwork/lnd/lnwallet/chancloser"
15
        "github.com/lightningnetwork/lnd/lnwire"
16
)
17

18
var (
19
        errShuttingDown = errors.New("server shutting down")
20

21
        // errCustomLength is returned when our custom error's length exceeds
22
        // our maximum.
23
        errCustomLength = fmt.Errorf("custom error message exceeds length "+
24
                "limit: %v", maxErrorLength)
25

26
        // errInvalidUpfrontShutdown is returned when we cannot parse the
27
        // upfront shutdown address returned.
28
        errInvalidUpfrontShutdown = fmt.Errorf("could not parse upfront " +
29
                "shutdown address")
30

31
        // errInsufficientReserve is returned when the reserve proposed by for
32
        // a channel is less than the dust limit originally supplied.
33
        errInsufficientReserve = fmt.Errorf("reserve lower than proposed dust " +
34
                "limit")
35

36
        // errAcceptWithError is returned when we get a response which accepts
37
        // a channel but ambiguously also sets a custom error message.
38
        errAcceptWithError = errors.New("channel acceptor response accepts " +
39
                "channel, but also includes custom error")
40

41
        // errMaxHtlcTooHigh is returned if our htlc count exceeds the number
42
        // hard-set by BOLT 2.
43
        errMaxHtlcTooHigh = fmt.Errorf("htlc limit exceeds spec limit of: %v",
44
                input.MaxHTLCNumber/2)
45

46
        // maxErrorLength is the maximum error length we allow the error we
47
        // send to our peer to be.
48
        maxErrorLength = 500
49
)
50

51
// chanAcceptInfo contains a request for a channel acceptor decision, and a
52
// channel that the response should be sent on.
53
type chanAcceptInfo struct {
54
        request  *ChannelAcceptRequest
55
        response chan *ChannelAcceptResponse
56
}
57

58
// RPCAcceptor represents the RPC-controlled variant of the ChannelAcceptor.
59
// One RPCAcceptor allows one RPC client.
60
type RPCAcceptor struct {
61
        // receive is a function from which we receive channel acceptance
62
        // decisions. Note that this function is expected to block.
63
        receive func() (*lnrpc.ChannelAcceptResponse, error)
64

65
        // send is a function which sends requests for channel acceptance
66
        // decisions into our rpc stream.
67
        send func(request *lnrpc.ChannelAcceptRequest) error
68

69
        // requests is a channel that we send requests for a acceptor response
70
        // into.
71
        requests chan *chanAcceptInfo
72

73
        // timeout is the amount of time we allow the channel acceptance
74
        // decision to take. This time includes the time to send a query to the
75
        // acceptor, and the time it takes to receive a response.
76
        timeout time.Duration
77

78
        // params are our current chain params.
79
        params *chaincfg.Params
80

81
        // done is closed when the rpc client terminates.
82
        done chan struct{}
83

84
        // quit is closed when lnd is shutting down.
85
        quit chan struct{}
86

87
        wg sync.WaitGroup
88
}
89

90
// Accept is a predicate on the ChannelAcceptRequest which is sent to the RPC
91
// client who will respond with the ultimate decision. This function passes the
92
// request into the acceptor's requests channel, and returns the response it
93
// receives, failing the request if the timeout elapses.
94
//
95
// NOTE: Part of the ChannelAcceptor interface.
96
func (r *RPCAcceptor) Accept(req *ChannelAcceptRequest) *ChannelAcceptResponse {
9✔
97
        respChan := make(chan *ChannelAcceptResponse, 1)
9✔
98

9✔
99
        newRequest := &chanAcceptInfo{
9✔
100
                request:  req,
9✔
101
                response: respChan,
9✔
102
        }
9✔
103

9✔
104
        // timeout is the time after which ChannelAcceptRequests expire.
9✔
105
        timeout := time.After(r.timeout)
9✔
106

9✔
107
        // Create a rejection response which we can use for the cases where we
9✔
108
        // reject the channel.
9✔
109
        rejectChannel := NewChannelAcceptResponse(
9✔
110
                false, errChannelRejected, nil, 0, 0, 0, 0, 0, 0, false,
9✔
111
        )
9✔
112

9✔
113
        // Send the request to the newRequests channel.
9✔
114
        select {
9✔
115
        case r.requests <- newRequest:
9✔
116

117
        case <-timeout:
×
118
                log.Errorf("RPCAcceptor returned false - reached timeout of %v",
×
119
                        r.timeout)
×
120
                return rejectChannel
×
121

122
        case <-r.done:
×
123
                return rejectChannel
×
124

125
        case <-r.quit:
×
126
                return rejectChannel
×
127
        }
128

129
        // Receive the response and return it. If no response has been received
130
        // in AcceptorTimeout, then return false.
131
        select {
9✔
132
        case resp := <-respChan:
9✔
133
                return resp
9✔
134

135
        case <-timeout:
×
136
                log.Errorf("RPCAcceptor returned false - reached timeout of %v",
×
137
                        r.timeout)
×
138
                return rejectChannel
×
139

140
        case <-r.done:
×
141
                return rejectChannel
×
142

143
        case <-r.quit:
×
144
                return rejectChannel
×
145
        }
146
}
147

148
// NewRPCAcceptor creates and returns an instance of the RPCAcceptor.
149
func NewRPCAcceptor(receive func() (*lnrpc.ChannelAcceptResponse, error),
150
        send func(*lnrpc.ChannelAcceptRequest) error, timeout time.Duration,
151
        params *chaincfg.Params, quit chan struct{}) *RPCAcceptor {
15✔
152

15✔
153
        return &RPCAcceptor{
15✔
154
                receive:  receive,
15✔
155
                send:     send,
15✔
156
                requests: make(chan *chanAcceptInfo),
15✔
157
                timeout:  timeout,
15✔
158
                params:   params,
15✔
159
                done:     make(chan struct{}),
15✔
160
                quit:     quit,
15✔
161
        }
15✔
162
}
15✔
163

164
// Run is the main loop for the RPC Acceptor. This function will block until
165
// it receives the signal that lnd is shutting down, or the rpc stream is
166
// cancelled by the client.
167
func (r *RPCAcceptor) Run() error {
7✔
168
        // Wait for our goroutines to exit before we return.
7✔
169
        defer r.wg.Wait()
7✔
170

7✔
171
        // Create a channel that responses from acceptors are sent into.
7✔
172
        responses := make(chan *lnrpc.ChannelAcceptResponse)
7✔
173

7✔
174
        // errChan is used by the receive loop to signal any errors that occur
7✔
175
        // during reading from the stream. This is primarily used to shutdown
7✔
176
        // the send loop in the case of an RPC client disconnecting.
7✔
177
        errChan := make(chan error, 1)
7✔
178

7✔
179
        // Start a goroutine to receive responses from the channel acceptor.
7✔
180
        // We expect the receive function to block, so it must be run in a
7✔
181
        // goroutine (otherwise we could not send more than one channel accept
7✔
182
        // request to the client).
7✔
183
        r.wg.Add(1)
7✔
184
        go func() {
14✔
185
                r.receiveResponses(errChan, responses)
7✔
186
                r.wg.Done()
7✔
187
        }()
7✔
188

189
        return r.sendAcceptRequests(errChan, responses)
7✔
190
}
191

192
// receiveResponses receives responses for our channel accept requests and
193
// dispatches them into the responses channel provided, sending any errors that
194
// occur into the error channel provided.
195
func (r *RPCAcceptor) receiveResponses(errChan chan error,
196
        responses chan *lnrpc.ChannelAcceptResponse) {
7✔
197

7✔
198
        for {
19✔
199
                resp, err := r.receive()
12✔
200
                if err != nil {
19✔
201
                        errChan <- err
7✔
202
                        return
7✔
203
                }
7✔
204

205
                var pendingID [32]byte
9✔
206
                copy(pendingID[:], resp.PendingChanId)
9✔
207

9✔
208
                openChanResp := &lnrpc.ChannelAcceptResponse{
9✔
209
                        Accept:          resp.Accept,
9✔
210
                        PendingChanId:   pendingID[:],
9✔
211
                        Error:           resp.Error,
9✔
212
                        UpfrontShutdown: resp.UpfrontShutdown,
9✔
213
                        CsvDelay:        resp.CsvDelay,
9✔
214
                        ReserveSat:      resp.ReserveSat,
9✔
215
                        InFlightMaxMsat: resp.InFlightMaxMsat,
9✔
216
                        MaxHtlcCount:    resp.MaxHtlcCount,
9✔
217
                        MinHtlcIn:       resp.MinHtlcIn,
9✔
218
                        MinAcceptDepth:  resp.MinAcceptDepth,
9✔
219
                        ZeroConf:        resp.ZeroConf,
9✔
220
                }
9✔
221

9✔
222
                // We have received a decision for one of our channel
9✔
223
                // acceptor requests.
9✔
224
                select {
9✔
225
                case responses <- openChanResp:
9✔
226

227
                case <-r.done:
×
228
                        return
×
229

230
                case <-r.quit:
×
231
                        return
×
232
                }
233
        }
234
}
235

236
// sendAcceptRequests handles channel acceptor requests sent to us by our
237
// Accept() function, dispatching them to our acceptor stream and coordinating
238
// return of responses to their callers.
239
func (r *RPCAcceptor) sendAcceptRequests(errChan chan error,
240
        responses chan *lnrpc.ChannelAcceptResponse) error {
7✔
241

7✔
242
        // Close the done channel to indicate that the acceptor is no longer
7✔
243
        // listening and any in-progress requests should be terminated.
7✔
244
        defer close(r.done)
7✔
245

7✔
246
        // Create a map of pending channel IDs to our original open channel
7✔
247
        // request and a response channel. We keep the original channel open
7✔
248
        // message so that we can validate our response against it.
7✔
249
        acceptRequests := make(map[[32]byte]*chanAcceptInfo)
7✔
250

7✔
251
        for {
24✔
252
                //nolint:lll
17✔
253
                select {
17✔
254
                // Consume requests passed to us from our Accept() function and
255
                // send them into our stream.
256
                case newRequest := <-r.requests:
9✔
257

9✔
258
                        req := newRequest.request
9✔
259
                        pendingChanID := req.OpenChanMsg.PendingChannelID
9✔
260

9✔
261
                        // Map the channel commitment type to its RPC
9✔
262
                        // counterpart. Also determine whether the zero-conf or
9✔
263
                        // scid-alias channel types are set.
9✔
264
                        var (
9✔
265
                                commitmentType lnrpc.CommitmentType
9✔
266
                                wantsZeroConf  bool
9✔
267
                                wantsScidAlias bool
9✔
268
                        )
9✔
269

9✔
270
                        if req.OpenChanMsg.ChannelType != nil {
13✔
271
                                channelFeatures := lnwire.RawFeatureVector(
4✔
272
                                        *req.OpenChanMsg.ChannelType,
4✔
273
                                )
4✔
274
                                switch {
4✔
275
                                case channelFeatures.OnlyContains(
276
                                        lnwire.ZeroConfRequired,
277
                                        lnwire.ScidAliasRequired,
278
                                        lnwire.ScriptEnforcedLeaseRequired,
279
                                        lnwire.AnchorsZeroFeeHtlcTxRequired,
280
                                        lnwire.StaticRemoteKeyRequired,
281
                                ):
×
282
                                        commitmentType = lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE
×
283

284
                                case channelFeatures.OnlyContains(
285
                                        lnwire.ZeroConfRequired,
286
                                        lnwire.ScriptEnforcedLeaseRequired,
287
                                        lnwire.AnchorsZeroFeeHtlcTxRequired,
288
                                        lnwire.StaticRemoteKeyRequired,
289
                                ):
4✔
290
                                        commitmentType = lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE
4✔
291

292
                                case channelFeatures.OnlyContains(
293
                                        lnwire.ScidAliasRequired,
294
                                        lnwire.ScriptEnforcedLeaseRequired,
295
                                        lnwire.AnchorsZeroFeeHtlcTxRequired,
296
                                        lnwire.StaticRemoteKeyRequired,
297
                                ):
×
298
                                        commitmentType = lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE
×
299

300
                                case channelFeatures.OnlyContains(
301
                                        lnwire.ScriptEnforcedLeaseRequired,
302
                                        lnwire.AnchorsZeroFeeHtlcTxRequired,
303
                                        lnwire.StaticRemoteKeyRequired,
304
                                ):
×
305
                                        commitmentType = lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE
×
306

307
                                case channelFeatures.OnlyContains(
308
                                        lnwire.ZeroConfRequired,
309
                                        lnwire.ScidAliasRequired,
310
                                        lnwire.AnchorsZeroFeeHtlcTxRequired,
311
                                        lnwire.StaticRemoteKeyRequired,
312
                                ):
×
313
                                        commitmentType = lnrpc.CommitmentType_ANCHORS
×
314

315
                                case channelFeatures.OnlyContains(
316
                                        lnwire.ZeroConfRequired,
317
                                        lnwire.AnchorsZeroFeeHtlcTxRequired,
318
                                        lnwire.StaticRemoteKeyRequired,
319
                                ):
4✔
320
                                        commitmentType = lnrpc.CommitmentType_ANCHORS
4✔
321

322
                                case channelFeatures.OnlyContains(
323
                                        lnwire.ScidAliasRequired,
324
                                        lnwire.AnchorsZeroFeeHtlcTxRequired,
325
                                        lnwire.StaticRemoteKeyRequired,
326
                                ):
4✔
327
                                        commitmentType = lnrpc.CommitmentType_ANCHORS
4✔
328

329
                                case channelFeatures.OnlyContains(
330
                                        lnwire.AnchorsZeroFeeHtlcTxRequired,
331
                                        lnwire.StaticRemoteKeyRequired,
332
                                ):
4✔
333
                                        commitmentType = lnrpc.CommitmentType_ANCHORS
4✔
334

335
                                case channelFeatures.OnlyContains(
336
                                        lnwire.SimpleTaprootChannelsRequiredStaging,
337
                                        lnwire.ZeroConfRequired,
338
                                        lnwire.ScidAliasRequired,
339
                                ):
×
340
                                        commitmentType = lnrpc.CommitmentType_SIMPLE_TAPROOT
×
341

342
                                case channelFeatures.OnlyContains(
343
                                        lnwire.SimpleTaprootChannelsRequiredStaging,
344
                                        lnwire.ZeroConfRequired,
345
                                ):
4✔
346
                                        commitmentType = lnrpc.CommitmentType_SIMPLE_TAPROOT
4✔
347

348
                                case channelFeatures.OnlyContains(
349
                                        lnwire.SimpleTaprootChannelsRequiredStaging,
350
                                        lnwire.ScidAliasRequired,
351
                                ):
×
352
                                        commitmentType = lnrpc.CommitmentType_SIMPLE_TAPROOT
×
353

354
                                case channelFeatures.OnlyContains(
355
                                        lnwire.SimpleTaprootChannelsRequiredStaging,
356
                                ):
×
357
                                        commitmentType = lnrpc.CommitmentType_SIMPLE_TAPROOT
×
358

359
                                case channelFeatures.OnlyContains(
360
                                        lnwire.SimpleTaprootOverlayChansRequired,
361
                                        lnwire.ZeroConfRequired,
362
                                        lnwire.ScidAliasRequired,
NEW
363
                                ):
×
NEW
364
                                        commitmentType = lnrpc.CommitmentType_SIMPLE_TAPROOT_OVERLAY
×
365

366
                                case channelFeatures.OnlyContains(
367
                                        lnwire.SimpleTaprootOverlayChansRequired,
368
                                        lnwire.ZeroConfRequired,
NEW
369
                                ):
×
NEW
370
                                        commitmentType = lnrpc.CommitmentType_SIMPLE_TAPROOT_OVERLAY
×
371

372
                                case channelFeatures.OnlyContains(
373
                                        lnwire.SimpleTaprootOverlayChansRequired,
374
                                        lnwire.ScidAliasRequired,
NEW
375
                                ):
×
NEW
376
                                        commitmentType = lnrpc.CommitmentType_SIMPLE_TAPROOT_OVERLAY
×
377

378
                                case channelFeatures.OnlyContains(
379
                                        lnwire.SimpleTaprootOverlayChansRequired,
NEW
380
                                ):
×
NEW
381
                                        commitmentType = lnrpc.CommitmentType_SIMPLE_TAPROOT_OVERLAY
×
382

383
                                case channelFeatures.OnlyContains(
384
                                        lnwire.StaticRemoteKeyRequired,
385
                                ):
4✔
386
                                        commitmentType = lnrpc.CommitmentType_STATIC_REMOTE_KEY
4✔
387

388
                                case channelFeatures.OnlyContains():
×
389
                                        commitmentType = lnrpc.CommitmentType_LEGACY
×
390

391
                                default:
×
392
                                        log.Warnf("Unhandled commitment type "+
×
393
                                                "in channel acceptor request: %v",
×
394
                                                req.OpenChanMsg.ChannelType)
×
395
                                }
396

397
                                if channelFeatures.IsSet(
4✔
398
                                        lnwire.ZeroConfRequired,
4✔
399
                                ) {
8✔
400

4✔
401
                                        wantsZeroConf = true
4✔
402
                                }
4✔
403

404
                                if channelFeatures.IsSet(
4✔
405
                                        lnwire.ScidAliasRequired,
4✔
406
                                ) {
8✔
407

4✔
408
                                        wantsScidAlias = true
4✔
409
                                }
4✔
410
                        }
411

412
                        acceptRequests[pendingChanID] = newRequest
9✔
413

9✔
414
                        // A ChannelAcceptRequest has been received, send it to the client.
9✔
415
                        chanAcceptReq := &lnrpc.ChannelAcceptRequest{
9✔
416
                                NodePubkey:       req.Node.SerializeCompressed(),
9✔
417
                                ChainHash:        req.OpenChanMsg.ChainHash[:],
9✔
418
                                PendingChanId:    req.OpenChanMsg.PendingChannelID[:],
9✔
419
                                FundingAmt:       uint64(req.OpenChanMsg.FundingAmount),
9✔
420
                                PushAmt:          uint64(req.OpenChanMsg.PushAmount),
9✔
421
                                DustLimit:        uint64(req.OpenChanMsg.DustLimit),
9✔
422
                                MaxValueInFlight: uint64(req.OpenChanMsg.MaxValueInFlight),
9✔
423
                                ChannelReserve:   uint64(req.OpenChanMsg.ChannelReserve),
9✔
424
                                MinHtlc:          uint64(req.OpenChanMsg.HtlcMinimum),
9✔
425
                                FeePerKw:         uint64(req.OpenChanMsg.FeePerKiloWeight),
9✔
426
                                CsvDelay:         uint32(req.OpenChanMsg.CsvDelay),
9✔
427
                                MaxAcceptedHtlcs: uint32(req.OpenChanMsg.MaxAcceptedHTLCs),
9✔
428
                                ChannelFlags:     uint32(req.OpenChanMsg.ChannelFlags),
9✔
429
                                CommitmentType:   commitmentType,
9✔
430
                                WantsZeroConf:    wantsZeroConf,
9✔
431
                                WantsScidAlias:   wantsScidAlias,
9✔
432
                        }
9✔
433

9✔
434
                        if err := r.send(chanAcceptReq); err != nil {
9✔
435
                                return err
×
436
                        }
×
437

438
                // Process newly received responses from our channel acceptor,
439
                // looking the original request up in our map of requests and
440
                // dispatching the response.
441
                case resp := <-responses:
9✔
442
                        // Look up the appropriate channel to send on given the
9✔
443
                        // pending ID. If a channel is found, send the response
9✔
444
                        // over it.
9✔
445
                        var pendingID [32]byte
9✔
446
                        copy(pendingID[:], resp.PendingChanId)
9✔
447
                        requestInfo, ok := acceptRequests[pendingID]
9✔
448
                        if !ok {
13✔
449
                                continue
4✔
450
                        }
451

452
                        // Validate the response we have received. If it is not
453
                        // valid, we log our error and proceed to deliver the
454
                        // rejection.
455
                        accept, acceptErr, shutdown, err := r.validateAcceptorResponse(
9✔
456
                                requestInfo.request.OpenChanMsg.DustLimit, resp,
9✔
457
                        )
9✔
458
                        if err != nil {
11✔
459
                                log.Errorf("Invalid acceptor response: %v", err)
2✔
460
                        }
2✔
461

462
                        requestInfo.response <- NewChannelAcceptResponse(
9✔
463
                                accept, acceptErr, shutdown,
9✔
464
                                uint16(resp.CsvDelay),
9✔
465
                                uint16(resp.MaxHtlcCount),
9✔
466
                                uint16(resp.MinAcceptDepth),
9✔
467
                                btcutil.Amount(resp.ReserveSat),
9✔
468
                                lnwire.MilliSatoshi(resp.InFlightMaxMsat),
9✔
469
                                lnwire.MilliSatoshi(resp.MinHtlcIn),
9✔
470
                                resp.ZeroConf,
9✔
471
                        )
9✔
472

9✔
473
                        // Delete the channel from the acceptRequests map.
9✔
474
                        delete(acceptRequests, pendingID)
9✔
475

476
                // If we failed to receive from our acceptor, we exit.
477
                case err := <-errChan:
4✔
478
                        log.Errorf("Received an error: %v, shutting down", err)
4✔
479
                        return err
4✔
480

481
                // Exit if we are shutting down.
482
                case <-r.quit:
3✔
483
                        return errShuttingDown
3✔
484
                }
485
        }
486
}
487

488
// validateAcceptorResponse validates the response we get from the channel
489
// acceptor, returning a boolean indicating whether to accept the channel, an
490
// error to send to the peer, and any validation errors that occurred.
491
func (r *RPCAcceptor) validateAcceptorResponse(dustLimit btcutil.Amount,
492
        req *lnrpc.ChannelAcceptResponse) (bool, error, lnwire.DeliveryAddress,
493
        error) {
17✔
494

17✔
495
        channelStr := hex.EncodeToString(req.PendingChanId)
17✔
496

17✔
497
        // Check that the max htlc count is within the BOLT 2 hard-limit of 483.
17✔
498
        // The initiating side should fail values above this anyway, but we
17✔
499
        // catch the invalid user input here.
17✔
500
        if req.MaxHtlcCount > input.MaxHTLCNumber/2 {
18✔
501
                log.Errorf("Max htlc count: %v for channel: %v is greater "+
1✔
502
                        "than limit of: %v", req.MaxHtlcCount, channelStr,
1✔
503
                        input.MaxHTLCNumber/2)
1✔
504

1✔
505
                return false, errChannelRejected, nil, errMaxHtlcTooHigh
1✔
506
        }
1✔
507

508
        // Ensure that the reserve that has been proposed, if it is set, is at
509
        // least the dust limit that was proposed by the remote peer. This is
510
        // required by BOLT 2.
511
        reserveSat := btcutil.Amount(req.ReserveSat)
16✔
512
        if reserveSat != 0 && reserveSat < dustLimit {
18✔
513
                log.Errorf("Remote reserve: %v sat for channel: %v must be "+
2✔
514
                        "at least equal to proposed dust limit: %v",
2✔
515
                        req.ReserveSat, channelStr, dustLimit)
2✔
516

2✔
517
                return false, errChannelRejected, nil, errInsufficientReserve
2✔
518
        }
2✔
519

520
        // Attempt to parse the upfront shutdown address provided.
521
        upfront, err := chancloser.ParseUpfrontShutdownAddress(
14✔
522
                req.UpfrontShutdown, r.params,
14✔
523
        )
14✔
524
        if err != nil {
15✔
525
                log.Errorf("Could not parse upfront shutdown for "+
1✔
526
                        "%v: %v", channelStr, err)
1✔
527

1✔
528
                return false, errChannelRejected, nil, errInvalidUpfrontShutdown
1✔
529
        }
1✔
530

531
        // Check that the custom error provided is valid.
532
        if len(req.Error) > maxErrorLength {
14✔
533
                return false, errChannelRejected, nil, errCustomLength
1✔
534
        }
1✔
535

536
        var haveCustomError = len(req.Error) != 0
12✔
537

12✔
538
        switch {
12✔
539
        // If accept is true, but we also have an error specified, we fail
540
        // because this result is ambiguous.
541
        case req.Accept && haveCustomError:
2✔
542
                return false, errChannelRejected, nil, errAcceptWithError
2✔
543

544
        // If we accept without an error message, we can just return a nil
545
        // error.
546
        case req.Accept:
6✔
547
                return true, nil, upfront, nil
6✔
548

549
        // If we reject the channel, and have a custom error, then we use it.
550
        case haveCustomError:
2✔
551
                return false, fmt.Errorf(req.Error), nil, nil
2✔
552

553
        // Otherwise, we have rejected the channel with no custom error, so we
554
        // just use a generic error to fail the channel.
555
        default:
6✔
556
                return false, errChannelRejected, nil, nil
6✔
557
        }
558
}
559

560
// A compile-time constraint to ensure RPCAcceptor implements the ChannelAcceptor
561
// interface.
562
var _ ChannelAcceptor = (*RPCAcceptor)(nil)
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