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

lightningnetwork / lnd / 13586005509

28 Feb 2025 10:14AM UTC coverage: 68.629% (+9.9%) from 58.77%
13586005509

Pull #9521

github

web-flow
Merge 37d3a70a5 into 8532955b3
Pull Request #9521: unit: remove GOACC, use Go 1.20 native coverage functionality

129950 of 189351 relevant lines covered (68.63%)

23726.46 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 {
8✔
97
        respChan := make(chan *ChannelAcceptResponse, 1)
8✔
98

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

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

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

8✔
113
        // Send the request to the newRequests channel.
8✔
114
        select {
8✔
115
        case r.requests <- newRequest:
8✔
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 {
8✔
132
        case resp := <-respChan:
8✔
133
                return resp
8✔
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 {
14✔
152

14✔
153
        return &RPCAcceptor{
14✔
154
                receive:  receive,
14✔
155
                send:     send,
14✔
156
                requests: make(chan *chanAcceptInfo),
14✔
157
                timeout:  timeout,
14✔
158
                params:   params,
14✔
159
                done:     make(chan struct{}),
14✔
160
                quit:     quit,
14✔
161
        }
14✔
162
}
14✔
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 {
6✔
168
        // Wait for our goroutines to exit before we return.
6✔
169
        defer r.wg.Wait()
6✔
170

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

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

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

189
        return r.sendAcceptRequests(errChan, responses)
6✔
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) {
6✔
197

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

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

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

8✔
222
                // We have received a decision for one of our channel
8✔
223
                // acceptor requests.
8✔
224
                select {
8✔
225
                case responses <- openChanResp:
8✔
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 {
6✔
241

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

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

6✔
251
        for {
22✔
252
                //nolint:ll
16✔
253
                select {
16✔
254
                // Consume requests passed to us from our Accept() function and
255
                // send them into our stream.
256
                case newRequest := <-r.requests:
8✔
257

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

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

8✔
270
                        if req.OpenChanMsg.ChannelType != nil {
11✔
271
                                channelFeatures := lnwire.RawFeatureVector(
3✔
272
                                        *req.OpenChanMsg.ChannelType,
3✔
273
                                )
3✔
274
                                switch {
3✔
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
                                ):
3✔
290
                                        commitmentType = lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE
3✔
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
                                ):
3✔
320
                                        commitmentType = lnrpc.CommitmentType_ANCHORS
3✔
321

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

329
                                case channelFeatures.OnlyContains(
330
                                        lnwire.AnchorsZeroFeeHtlcTxRequired,
331
                                        lnwire.StaticRemoteKeyRequired,
332
                                ):
3✔
333
                                        commitmentType = lnrpc.CommitmentType_ANCHORS
3✔
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
                                ):
3✔
346
                                        commitmentType = lnrpc.CommitmentType_SIMPLE_TAPROOT
3✔
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,
363
                                ):
×
364
                                        commitmentType = lnrpc.CommitmentType_SIMPLE_TAPROOT_OVERLAY
×
365

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

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

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

383
                                case channelFeatures.OnlyContains(
384
                                        lnwire.StaticRemoteKeyRequired,
385
                                ):
3✔
386
                                        commitmentType = lnrpc.CommitmentType_STATIC_REMOTE_KEY
3✔
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(
3✔
398
                                        lnwire.ZeroConfRequired,
3✔
399
                                ) {
6✔
400

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

404
                                if channelFeatures.IsSet(
3✔
405
                                        lnwire.ScidAliasRequired,
3✔
406
                                ) {
6✔
407

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

412
                        acceptRequests[pendingChanID] = newRequest
8✔
413

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

8✔
434
                        if err := r.send(chanAcceptReq); err != nil {
8✔
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:
8✔
442
                        // Look up the appropriate channel to send on given the
8✔
443
                        // pending ID. If a channel is found, send the response
8✔
444
                        // over it.
8✔
445
                        var pendingID [32]byte
8✔
446
                        copy(pendingID[:], resp.PendingChanId)
8✔
447
                        requestInfo, ok := acceptRequests[pendingID]
8✔
448
                        if !ok {
11✔
449
                                continue
3✔
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(
8✔
456
                                requestInfo.request.OpenChanMsg.DustLimit, resp,
8✔
457
                        )
8✔
458
                        if err != nil {
10✔
459
                                log.Errorf("Invalid acceptor response: %v", err)
2✔
460
                        }
2✔
461

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

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

476
                // If we failed to receive from our acceptor, we exit.
477
                case err := <-errChan:
3✔
478
                        log.Errorf("Received an error: %v, shutting down", err)
3✔
479
                        return err
3✔
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) {
16✔
494

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

16✔
497
        // Check that the max htlc count is within the BOLT 2 hard-limit of 483.
16✔
498
        // The initiating side should fail values above this anyway, but we
16✔
499
        // catch the invalid user input here.
16✔
500
        if req.MaxHtlcCount > input.MaxHTLCNumber/2 {
17✔
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)
15✔
512
        if reserveSat != 0 && reserveSat < dustLimit {
17✔
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(
13✔
522
                req.UpfrontShutdown, r.params,
13✔
523
        )
13✔
524
        if err != nil {
14✔
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 {
13✔
533
                return false, errChannelRejected, nil, errCustomLength
1✔
534
        }
1✔
535

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

11✔
538
        switch {
11✔
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:
5✔
547
                return true, nil, upfront, nil
5✔
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:
5✔
556
                return false, errChannelRejected, nil, nil
5✔
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