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

lightningnetwork / lnd / 12199391122

06 Dec 2024 01:10PM UTC coverage: 49.807% (-9.1%) from 58.933%
12199391122

push

github

web-flow
Merge pull request #9337 from Guayaba221/patch-1

chore: fix typo in ruby.md

100137 of 201051 relevant lines covered (49.81%)

2.07 hits per line

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

4✔
270
                        if req.OpenChanMsg.ChannelType != nil {
8✔
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,
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
                                ):
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
4✔
413

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

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

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

4✔
473
                        // Delete the channel from the acceptRequests map.
4✔
474
                        delete(acceptRequests, pendingID)
4✔
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:
×
483
                        return errShuttingDown
×
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) {
4✔
494

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

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

×
505
                return false, errChannelRejected, nil, errMaxHtlcTooHigh
×
506
        }
×
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)
4✔
512
        if reserveSat != 0 && reserveSat < dustLimit {
4✔
513
                log.Errorf("Remote reserve: %v sat for channel: %v must be "+
×
514
                        "at least equal to proposed dust limit: %v",
×
515
                        req.ReserveSat, channelStr, dustLimit)
×
516

×
517
                return false, errChannelRejected, nil, errInsufficientReserve
×
518
        }
×
519

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

×
528
                return false, errChannelRejected, nil, errInvalidUpfrontShutdown
×
529
        }
×
530

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

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

4✔
538
        switch {
4✔
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:
×
542
                return false, errChannelRejected, nil, errAcceptWithError
×
543

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

549
        // If we reject the channel, and have a custom error, then we use it.
550
        case haveCustomError:
×
551
                return false, fmt.Errorf(req.Error), nil, nil
×
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:
4✔
556
                return false, errChannelRejected, nil, nil
4✔
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