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

lightningnetwork / lnd / 15778860361

20 Jun 2025 12:23PM UTC coverage: 68.208% (+0.07%) from 68.143%
15778860361

Pull #9752

github

web-flow
Merge 831fefef7 into 7857d2c6a
Pull Request #9752: routerrpc: reject payment to invoice that don't have payment secret or blinded paths

10 of 14 new or added lines in 2 files covered. (71.43%)

2644 existing lines in 29 files now uncovered.

134706 of 197494 relevant lines covered (68.21%)

22122.25 hits per line

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

81.67
/accessman.go
1
package lnd
2

3
import (
4
        "context"
5
        "fmt"
6
        "maps"
7
        "sync"
8

9
        "github.com/btcsuite/btcd/btcec/v2"
10
        "github.com/btcsuite/btclog/v2"
11
        "github.com/lightningnetwork/lnd/channeldb"
12
        "github.com/lightningnetwork/lnd/lnutils"
13
)
14

15
// accessMan is responsible for managing the server's access permissions.
16
type accessMan struct {
17
        cfg *accessManConfig
18

19
        // banScoreMtx is used for the server's ban tracking. If the server
20
        // mutex is also going to be locked, ensure that this is locked after
21
        // the server mutex.
22
        banScoreMtx sync.RWMutex
23

24
        // peerCounts is a mapping from remote public key to {bool, uint64}
25
        // where the bool indicates that we have an open/closed channel with
26
        // the peer and where the uint64 indicates the number of pending-open
27
        // channels we currently have with them. This mapping will be used to
28
        // determine access permissions for the peer. The map key is the
29
        // string-version of the serialized public key.
30
        //
31
        // NOTE: This MUST be accessed with the banScoreMtx held.
32
        peerCounts map[string]channeldb.ChanCount
33

34
        // peerScores stores each connected peer's access status. The map key
35
        // is the string-version of the serialized public key.
36
        //
37
        // NOTE: This MUST be accessed with the banScoreMtx held.
38
        peerScores map[string]peerSlotStatus
39

40
        // numRestricted tracks the number of peers with restricted access in
41
        // peerScores. This MUST be accessed with the banScoreMtx held.
42
        numRestricted int64
43
}
44

45
type accessManConfig struct {
46
        // initAccessPerms checks the channeldb for initial access permissions
47
        // and then populates the peerCounts and peerScores maps.
48
        initAccessPerms func() (map[string]channeldb.ChanCount, error)
49

50
        // shouldDisconnect determines whether we should disconnect a peer or
51
        // not.
52
        shouldDisconnect func(*btcec.PublicKey) (bool, error)
53

54
        // maxRestrictedSlots is the number of restricted slots we'll allocate.
55
        maxRestrictedSlots int64
56
}
57

58
func newAccessMan(cfg *accessManConfig) (*accessMan, error) {
59
        a := &accessMan{
60
                cfg:        cfg,
61
                peerCounts: make(map[string]channeldb.ChanCount),
62
                peerScores: make(map[string]peerSlotStatus),
14✔
63
        }
14✔
64

14✔
65
        counts, err := a.cfg.initAccessPerms()
14✔
66
        if err != nil {
14✔
67
                return nil, err
14✔
68
        }
14✔
69

14✔
70
        // We'll populate the server's peerCounts map with the counts fetched
14✔
UNCOV
71
        // via initAccessPerms. Also note that we haven't yet connected to the
×
UNCOV
72
        // peers.
×
73
        maps.Copy(a.peerCounts, counts)
74

75
        acsmLog.Info("Access Manager initialized")
76

77
        return a, nil
14✔
78
}
14✔
79

14✔
80
// assignPeerPerms assigns a new peer its permissions. This does not track the
14✔
81
// access in the maps. This is intentional.
14✔
82
func (a *accessMan) assignPeerPerms(remotePub *btcec.PublicKey) (
83
        peerAccessStatus, error) {
84

85
        ctx := btclog.WithCtx(
86
                context.TODO(), lnutils.LogPubKey("peer", remotePub),
25✔
87
        )
25✔
88

25✔
89
        peerMapKey := string(remotePub.SerializeCompressed())
25✔
90

25✔
91
        acsmLog.DebugS(ctx, "Assigning permissions")
25✔
92

25✔
93
        // Default is restricted unless the below filters say otherwise.
25✔
94
        access := peerStatusRestricted
44✔
95

29✔
96
        // Lock banScoreMtx for reading so that we can update the banning maps
10✔
97
        // below.
10✔
98
        a.banScoreMtx.RLock()
10✔
99
        if count, found := a.peerCounts[peerMapKey]; found {
10✔
100
                if count.HasOpenOrClosedChan {
10✔
101
                        acsmLog.DebugS(ctx, "Peer has open/closed channel, "+
10✔
102
                                "assigning protected access")
103

19✔
104
                        access = peerStatusProtected
7✔
105
                } else if count.PendingOpenCount != 0 {
7✔
106
                        acsmLog.DebugS(ctx, "Peer has pending channel(s), "+
7✔
107
                                "assigning temporary access")
7✔
108

7✔
109
                        access = peerStatusTemporary
7✔
110
                }
111
        }
5✔
112
        a.banScoreMtx.RUnlock()
113

114
        // Exit early if the peer status is no longer restricted.
115
        if access != peerStatusRestricted {
9✔
116
                return access, nil
11✔
117
        }
2✔
118

2✔
119
        // Check whether this peer is banned.
2✔
120
        shouldDisconnect, err := a.cfg.shouldDisconnect(remotePub)
2✔
121
        if err != nil {
2✔
122
                acsmLog.ErrorS(ctx, "Error checking disconnect status", err)
123

7✔
124
                // Access is restricted here.
125
                return access, err
126
        }
127

128
        if shouldDisconnect {
129
                acsmLog.WarnS(ctx, "Peer is banned, assigning restricted access",
20✔
130
                        ErrGossiperBan)
20✔
131

20✔
132
                // Access is restricted here.
20✔
133
                return access, ErrGossiperBan
20✔
134
        }
20✔
135

20✔
136
        // If we've reached this point and access hasn't changed from
20✔
137
        // restricted, then we need to check if we even have a slot for this
20✔
138
        // peer.
20✔
139
        acsmLog.DebugS(ctx, "Peer has no channels, assigning restricted access")
20✔
140

20✔
141
        a.banScoreMtx.RLock()
20✔
142
        defer a.banScoreMtx.RUnlock()
20✔
143

33✔
144
        if a.numRestricted >= a.cfg.maxRestrictedSlots {
13✔
145
                acsmLog.WarnS(ctx, "No more restricted slots available, "+
13✔
146
                        "denying peer", ErrNoMoreRestrictedAccessSlots,
147
                        "num_restricted", a.numRestricted, "max_restricted",
148
                        a.cfg.maxRestrictedSlots)
149

150
                return access, ErrNoMoreRestrictedAccessSlots
10✔
151
        }
10✔
UNCOV
152

×
UNCOV
153
        return access, nil
×
UNCOV
154
}
×
UNCOV
155

×
UNCOV
156
// newPendingOpenChan is called after the pending-open channel has been
×
157
// committed to the database. This may transition a restricted-access peer to a
158
// temporary-access peer.
11✔
159
func (a *accessMan) newPendingOpenChan(remotePub *btcec.PublicKey) error {
1✔
160
        a.banScoreMtx.Lock()
1✔
161
        defer a.banScoreMtx.Unlock()
1✔
162

1✔
163
        ctx := btclog.WithCtx(
1✔
164
                context.TODO(), lnutils.LogPubKey("peer", remotePub),
1✔
165
        )
166

167
        acsmLog.DebugS(ctx, "Processing new pending open channel")
168

169
        peerMapKey := string(remotePub.SerializeCompressed())
9✔
170

9✔
171
        // Fetch the peer's access status from peerScores.
9✔
172
        status, found := a.peerScores[peerMapKey]
12✔
173
        if !found {
3✔
174
                acsmLog.ErrorS(ctx, "Peer score not found", ErrNoPeerScore)
3✔
175

3✔
176
                // If we didn't find the peer, we'll return an error.
177
                return ErrNoPeerScore
6✔
178
        }
6✔
179

6✔
180
        switch status.state {
10✔
181
        case peerStatusProtected:
4✔
182
                acsmLog.DebugS(ctx, "Peer already protected, no change")
4✔
183

4✔
184
                // If this peer's access status is protected, we don't need to
4✔
185
                // do anything.
4✔
186
                return nil
4✔
187

4✔
188
        case peerStatusTemporary:
189
                // If this peer's access status is temporary, we'll need to
5✔
190
                // update the peerCounts map. The peer's access status will stay
191
                // temporary.
192
                peerCount, found := a.peerCounts[peerMapKey]
193
                if !found {
194
                        // Error if we did not find any info in peerCounts.
195
                        acsmLog.ErrorS(ctx, "Pending peer info not found",
4✔
196
                                ErrNoPendingPeerInfo)
4✔
197

4✔
198
                        return ErrNoPendingPeerInfo
4✔
199
                }
4✔
200

4✔
201
                // Increment the pending channel amount.
4✔
202
                peerCount.PendingOpenCount += 1
4✔
203
                a.peerCounts[peerMapKey] = peerCount
4✔
204

4✔
205
                acsmLog.DebugS(ctx, "Peer is temporary, incremented "+
4✔
206
                        "pending count",
4✔
207
                        "pending_count", peerCount.PendingOpenCount)
4✔
208

4✔
209
        case peerStatusRestricted:
4✔
UNCOV
210
                // If the peer's access status is restricted, then we can
×
UNCOV
211
                // transition it to a temporary-access peer. We'll need to
×
UNCOV
212
                // update numRestricted and also peerScores. We'll also need to
×
UNCOV
213
                // update peerCounts.
×
UNCOV
214
                peerCount := channeldb.ChanCount{
×
215
                        HasOpenOrClosedChan: false,
216
                        PendingOpenCount:    1,
4✔
217
                }
3✔
218

3✔
219
                a.peerCounts[peerMapKey] = peerCount
3✔
220

3✔
221
                // A restricted-access slot has opened up.
3✔
222
                oldRestricted := a.numRestricted
3✔
223
                a.numRestricted -= 1
224

3✔
225
                a.peerScores[peerMapKey] = peerSlotStatus{
3✔
226
                        state: peerStatusTemporary,
3✔
227
                }
3✔
228

3✔
229
                acsmLog.InfoS(ctx, "Peer transitioned restricted -> "+
3✔
UNCOV
230
                        "temporary (pending open)",
×
UNCOV
231
                        "old_restricted", oldRestricted,
×
UNCOV
232
                        "new_restricted", a.numRestricted)
×
UNCOV
233

×
234
        default:
×
235
                // This should not be possible.
×
236
                err := fmt.Errorf("invalid peer access status %v for %x",
237
                        status.state, peerMapKey)
238
                acsmLog.ErrorS(ctx, "Invalid peer access status", err)
3✔
239

3✔
240
                return err
3✔
241
        }
3✔
242

3✔
243
        return nil
3✔
244
}
245

4✔
246
// newPendingCloseChan is called when a pending-open channel prematurely closes
4✔
247
// before the funding transaction has confirmed. This potentially demotes a
4✔
248
// temporary-access peer to a restricted-access peer. If no restricted-access
4✔
249
// slots are available, the peer will be disconnected.
4✔
250
func (a *accessMan) newPendingCloseChan(remotePub *btcec.PublicKey) error {
4✔
251
        a.banScoreMtx.Lock()
4✔
252
        defer a.banScoreMtx.Unlock()
4✔
253

4✔
254
        ctx := btclog.WithCtx(
4✔
255
                context.TODO(), lnutils.LogPubKey("peer", remotePub),
4✔
256
        )
4✔
257

4✔
258
        acsmLog.DebugS(ctx, "Processing pending channel close")
4✔
259

4✔
260
        peerMapKey := string(remotePub.SerializeCompressed())
4✔
261

4✔
262
        // Fetch the peer's access status from peerScores.
4✔
263
        status, found := a.peerScores[peerMapKey]
4✔
264
        if !found {
4✔
265
                acsmLog.ErrorS(ctx, "Peer score not found", ErrNoPeerScore)
4✔
266

4✔
267
                return ErrNoPeerScore
4✔
268
        }
4✔
269

UNCOV
270
        switch status.state {
×
271
        case peerStatusProtected:
×
272
                // If this peer is protected, we don't do anything.
×
273
                acsmLog.DebugS(ctx, "Peer is protected, no change")
×
274

×
275
                return nil
×
UNCOV
276

×
277
        case peerStatusTemporary:
278
                // If this peer is temporary, we need to check if it will
279
                // revert to a restricted-access peer.
4✔
280
                peerCount, found := a.peerCounts[peerMapKey]
281
                if !found {
282
                        acsmLog.ErrorS(ctx, "Pending peer info not found",
283
                                ErrNoPendingPeerInfo)
284

285
                        // Error if we did not find any info in peerCounts.
286
                        return ErrNoPendingPeerInfo
4✔
287
                }
4✔
288

4✔
289
                currentNumPending := peerCount.PendingOpenCount - 1
4✔
290

4✔
291
                acsmLog.DebugS(ctx, "Peer is temporary, decrementing "+
4✔
292
                        "pending count",
4✔
293
                        "pending_count", currentNumPending)
4✔
294

4✔
295
                if currentNumPending == 0 {
4✔
296
                        // Remove the entry from peerCounts.
4✔
297
                        delete(a.peerCounts, peerMapKey)
4✔
298

4✔
299
                        // If this is the only pending-open channel for this
4✔
300
                        // peer and it's getting removed, attempt to demote
4✔
UNCOV
301
                        // this peer to a restricted peer.
×
UNCOV
302
                        if a.numRestricted == a.cfg.maxRestrictedSlots {
×
UNCOV
303
                                // There are no available restricted slots, so
×
UNCOV
304
                                // we need to disconnect this peer. We leave
×
305
                                // this up to the caller.
306
                                acsmLog.WarnS(ctx, "Peer last pending "+
4✔
UNCOV
307
                                        "channel closed: ",
×
UNCOV
308
                                        ErrNoMoreRestrictedAccessSlots,
×
UNCOV
309
                                        "num_restricted", a.numRestricted,
×
UNCOV
310
                                        "max_restricted", a.cfg.maxRestrictedSlots)
×
UNCOV
311

×
312
                                return ErrNoMoreRestrictedAccessSlots
313
                        }
4✔
314

4✔
315
                        // Otherwise, there is an available restricted-access
4✔
316
                        // slot, so we can demote this peer.
4✔
317
                        a.peerScores[peerMapKey] = peerSlotStatus{
4✔
UNCOV
318
                                state: peerStatusRestricted,
×
UNCOV
319
                        }
×
UNCOV
320

×
UNCOV
321
                        // Update numRestricted.
×
UNCOV
322
                        oldRestricted := a.numRestricted
×
UNCOV
323
                        a.numRestricted++
×
324

325
                        acsmLog.InfoS(ctx, "Peer transitioned "+
4✔
326
                                "temporary -> restricted "+
4✔
327
                                "(last pending closed)",
4✔
328
                                "old_restricted", oldRestricted,
4✔
329
                                "new_restricted", a.numRestricted)
4✔
330

4✔
331
                        return nil
8✔
332
                }
4✔
333

4✔
334
                // Else, we don't need to demote this peer since it has other
4✔
335
                // pending-open channels with us.
4✔
336
                peerCount.PendingOpenCount = currentNumPending
4✔
337
                a.peerCounts[peerMapKey] = peerCount
4✔
338

5✔
339
                acsmLog.DebugS(ctx, "Peer still has other pending channels",
1✔
340
                        "pending_count", currentNumPending)
1✔
341

1✔
342
                return nil
1✔
343

1✔
344
        case peerStatusRestricted:
1✔
345
                // This should not be possible. This indicates an error.
1✔
346
                err := fmt.Errorf("invalid peer access state transition: "+
1✔
347
                        "pending close for restricted peer %x", peerMapKey)
1✔
348
                acsmLog.ErrorS(ctx, "Invalid peer access state transition", err)
1✔
349

1✔
350
                return err
351

352
        default:
353
                // This should not be possible.
3✔
354
                err := fmt.Errorf("invalid peer access status %v for %x",
3✔
355
                        status.state, peerMapKey)
3✔
356
                acsmLog.ErrorS(ctx, "Invalid peer access status", err)
3✔
357

3✔
358
                return err
3✔
359
        }
3✔
360
}
3✔
361

3✔
362
// newOpenChan is called when a pending-open channel becomes an open channel
3✔
363
// (i.e. the funding transaction has confirmed). If the remote peer is a
3✔
364
// temporary-access peer, it will be promoted to a protected-access peer.
3✔
365
func (a *accessMan) newOpenChan(remotePub *btcec.PublicKey) error {
3✔
366
        a.banScoreMtx.Lock()
3✔
367
        defer a.banScoreMtx.Unlock()
3✔
368

369
        ctx := btclog.WithCtx(
370
                context.TODO(), lnutils.LogPubKey("peer", remotePub),
371
        )
UNCOV
372

×
UNCOV
373
        acsmLog.DebugS(ctx, "Processing new open channel")
×
UNCOV
374

×
UNCOV
375
        peerMapKey := string(remotePub.SerializeCompressed())
×
UNCOV
376

×
UNCOV
377
        // Fetch the peer's access status from peerScores.
×
UNCOV
378
        status, found := a.peerScores[peerMapKey]
×
379
        if !found {
UNCOV
380
                // If we didn't find the peer, we'll return an error.
×
UNCOV
381
                acsmLog.ErrorS(ctx, "Peer score not found", ErrNoPeerScore)
×
UNCOV
382

×
UNCOV
383
                return ErrNoPeerScore
×
UNCOV
384
        }
×
UNCOV
385

×
UNCOV
386
        switch status.state {
×
387
        case peerStatusProtected:
UNCOV
388
                acsmLog.DebugS(ctx, "Peer already protected, no change")
×
UNCOV
389

×
UNCOV
390
                // If the peer's state is already protected, we don't need to do
×
UNCOV
391
                // anything more.
×
UNCOV
392
                return nil
×
UNCOV
393

×
UNCOV
394
        case peerStatusTemporary:
×
395
                // If the peer's state is temporary, we'll upgrade the peer to
396
                // a protected peer.
397
                peerCount, found := a.peerCounts[peerMapKey]
398
                if !found {
399
                        // Error if we did not find any info in peerCounts.
400
                        acsmLog.ErrorS(ctx, "Pending peer info not found",
401
                                ErrNoPendingPeerInfo)
4✔
402

4✔
403
                        return ErrNoPendingPeerInfo
4✔
404
                }
4✔
405

4✔
406
                peerCount.HasOpenOrClosedChan = true
4✔
407
                a.peerCounts[peerMapKey] = peerCount
4✔
408

4✔
409
                newStatus := peerSlotStatus{
4✔
410
                        state: peerStatusProtected,
4✔
411
                }
4✔
412
                a.peerScores[peerMapKey] = newStatus
4✔
413

4✔
414
                acsmLog.InfoS(ctx, "Peer transitioned temporary -> "+
4✔
415
                        "protected (channel opened)")
7✔
416

3✔
417
                return nil
3✔
418

3✔
419
        case peerStatusRestricted:
3✔
420
                // This should not be possible. For the server to receive a
3✔
421
                // state-transition event via NewOpenChan, the server must have
422
                // previously granted this peer "temporary" access. This
4✔
423
                // temporary access would not have been revoked or downgraded
3✔
424
                // without `CloseChannel` being called with the pending
3✔
425
                // argument set to true. This means that an open-channel state
3✔
426
                // transition would be impossible. Therefore, we can return an
3✔
427
                // error.
3✔
428
                err := fmt.Errorf("invalid peer access status: new open "+
3✔
429
                        "channel for restricted peer %x", peerMapKey)
430

4✔
431
                acsmLog.ErrorS(ctx, "Invalid peer access status", err)
4✔
432

4✔
433
                return err
4✔
434

4✔
435
        default:
×
436
                // This should not be possible.
×
437
                err := fmt.Errorf("invalid peer access status %v for %x",
×
438
                        status.state, peerMapKey)
×
439

×
440
                acsmLog.ErrorS(ctx, "Invalid peer access status", err)
×
441

442
                return err
4✔
443
        }
4✔
444
}
4✔
445

4✔
446
// checkIncomingConnBanScore checks whether, given the remote's public hex-
4✔
447
// encoded key, we should not accept this incoming connection or immediately
4✔
448
// disconnect. This does not assign to the server's peerScores maps. This is
4✔
449
// just an inbound filter that the brontide listeners use.
4✔
450
func (a *accessMan) checkIncomingConnBanScore(remotePub *btcec.PublicKey) (
4✔
451
        bool, error) {
4✔
452

4✔
453
        ctx := btclog.WithCtx(
4✔
454
                context.TODO(), lnutils.LogPubKey("peer", remotePub),
4✔
455
        )
4✔
456

UNCOV
457
        peerMapKey := string(remotePub.SerializeCompressed())
×
UNCOV
458

×
UNCOV
459
        acsmLog.TraceS(ctx, "Checking incoming connection ban score")
×
UNCOV
460

×
UNCOV
461
        a.banScoreMtx.RLock()
×
UNCOV
462
        defer a.banScoreMtx.RUnlock()
×
UNCOV
463

×
UNCOV
464
        if _, found := a.peerCounts[peerMapKey]; !found {
×
UNCOV
465
                acsmLog.DebugS(ctx, "Peer not found in counts, "+
×
UNCOV
466
                        "checking restricted slots")
×
UNCOV
467

×
UNCOV
468
                // Check numRestricted to see if there is an available slot. In
×
UNCOV
469
                // the future, it's possible to add better heuristics.
×
UNCOV
470
                if a.numRestricted < a.cfg.maxRestrictedSlots {
×
UNCOV
471
                        // There is an available slot.
×
472
                        acsmLog.DebugS(ctx, "Restricted slot available, "+
UNCOV
473
                                "accepting",
×
UNCOV
474
                                "num_restricted", a.numRestricted,
×
UNCOV
475
                                "max_restricted", a.cfg.maxRestrictedSlots)
×
UNCOV
476

×
UNCOV
477
                        return true, nil
×
UNCOV
478
                }
×
UNCOV
479

×
UNCOV
480
                // If there are no slots left, then we reject this connection.
×
481
                acsmLog.WarnS(ctx, "No restricted slots available, "+
482
                        "rejecting",
483
                        ErrNoMoreRestrictedAccessSlots,
484
                        "num_restricted", a.numRestricted,
485
                        "max_restricted", a.cfg.maxRestrictedSlots)
486

487
                return false, ErrNoMoreRestrictedAccessSlots
488
        }
489

490
        // Else, the peer is either protected or temporary.
491
        acsmLog.DebugS(ctx, "Peer found (protected/temporary), accepting")
492

493
        return true, nil
8✔
494
}
8✔
495

8✔
496
// addPeerAccess tracks a peer's access in the maps. This should be called when
8✔
497
// the peer has fully connected.
8✔
498
func (a *accessMan) addPeerAccess(remotePub *btcec.PublicKey,
8✔
499
        access peerAccessStatus) {
8✔
500

8✔
501
        ctx := btclog.WithCtx(
8✔
502
                context.TODO(), lnutils.LogPubKey("peer", remotePub),
8✔
503
        )
8✔
504

8✔
505
        acsmLog.DebugS(ctx, "Adding peer access", "access", access)
8✔
506

8✔
507
        // Add the remote public key to peerScores.
8✔
508
        a.banScoreMtx.Lock()
8✔
509
        defer a.banScoreMtx.Unlock()
14✔
510

6✔
511
        peerMapKey := string(remotePub.SerializeCompressed())
6✔
512

6✔
513
        a.peerScores[peerMapKey] = peerSlotStatus{state: access}
6✔
514

6✔
515
        // Increment numRestricted.
516
        if access == peerStatusRestricted {
5✔
517
                oldRestricted := a.numRestricted
5✔
518
                a.numRestricted++
5✔
519

8✔
520
                acsmLog.DebugS(ctx, "Incremented restricted slots",
3✔
521
                        "old_restricted", oldRestricted,
3✔
522
                        "new_restricted", a.numRestricted)
3✔
523
        }
3✔
524
}
525

5✔
526
// removePeerAccess removes the peer's access from the maps. This should be
5✔
527
// called when the peer has been disconnected.
5✔
528
func (a *accessMan) removePeerAccess(remotePub *btcec.PublicKey) {
5✔
529
        a.banScoreMtx.Lock()
5✔
530
        defer a.banScoreMtx.Unlock()
10✔
531

5✔
532
        ctx := btclog.WithCtx(
5✔
533
                context.TODO(), lnutils.LogPubKey("peer", remotePub),
5✔
534
        )
5✔
535

5✔
536
        acsmLog.DebugS(ctx, "Removing peer access")
5✔
537

5✔
538
        peerMapKey := string(remotePub.SerializeCompressed())
539

540
        status, found := a.peerScores[peerMapKey]
3✔
541
        if !found {
3✔
542
                acsmLog.InfoS(ctx, "Peer score not found during removal")
3✔
543
                return
3✔
544
        }
3✔
545

546
        if status.state == peerStatusRestricted {
547
                // If the status is restricted, then we decrement from
548
                // numRestrictedSlots.
549
                oldRestricted := a.numRestricted
550
                a.numRestricted--
14✔
551

14✔
552
                acsmLog.DebugS(ctx, "Decremented restricted slots",
14✔
553
                        "old_restricted", oldRestricted,
14✔
554
                        "new_restricted", a.numRestricted)
14✔
555
        }
14✔
556

14✔
557
        acsmLog.TraceS(ctx, "Deleting peer from peerScores")
14✔
558

14✔
559
        delete(a.peerScores, peerMapKey)
14✔
560
}
14✔
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