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

lightningnetwork / lnd / 13236757158

10 Feb 2025 08:39AM UTC coverage: 57.649% (-1.2%) from 58.815%
13236757158

Pull #9493

github

ziggie1984
lncli: for some cmds we don't replace the data of the response.

For some cmds it is not very practical to replace the json output
because we might pipe it into other commands. For example when
creating the route we want to pipe it into sendtoRoute.
Pull Request #9493: For some lncli cmds we should not replace the content with other data

0 of 9 new or added lines in 2 files covered. (0.0%)

19535 existing lines in 252 files now uncovered.

103517 of 179563 relevant lines covered (57.65%)

24878.49 hits per line

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

96.0
/watchtower/wtclient/candidate_iterator.go
1
package wtclient
2

3
import (
4
        "container/list"
5
        "net"
6
        "sync"
7

8
        "github.com/lightningnetwork/lnd/watchtower/wtdb"
9
)
10

11
// TowerCandidateIterator provides an abstraction for iterating through possible
12
// watchtower addresses when attempting to create a new session.
13
type TowerCandidateIterator interface {
14
        // AddCandidate adds a new candidate tower to the iterator. If the
15
        // candidate already exists, then any new addresses are added to it.
16
        AddCandidate(*Tower)
17

18
        // RemoveCandidate removes an existing candidate tower from the
19
        // iterator. An optional address can be provided to indicate a stale
20
        // tower address to remove it. If it isn't provided, then the tower is
21
        // completely removed from the iterator.
22
        RemoveCandidate(wtdb.TowerID, net.Addr) error
23

24
        // IsActive determines whether a given tower is exists within the
25
        // iterator.
26
        IsActive(wtdb.TowerID) bool
27

28
        // Reset clears any internal iterator state, making previously taken
29
        // candidates available as long as they remain in the set.
30
        Reset() error
31

32
        // GetTower gets the tower with the given ID from the iterator. If no
33
        // such tower is found then ErrTowerNotInIterator is returned.
34
        GetTower(id wtdb.TowerID) (*Tower, error)
35

36
        // Next returns the next candidate tower. The iterator is not required
37
        // to return results in any particular order.  If no more candidates are
38
        // available, ErrTowerCandidatesExhausted is returned.
39
        Next() (*Tower, error)
40
}
41

42
// towerListIterator is a linked-list backed TowerCandidateIterator.
43
type towerListIterator struct {
44
        mu            sync.Mutex
45
        queue         *list.List
46
        nextCandidate *list.Element
47
        candidates    map[wtdb.TowerID]*Tower
48
}
49

50
// Compile-time constraint to ensure *towerListIterator implements the
51
// TowerCandidateIterator interface.
52
var _ TowerCandidateIterator = (*towerListIterator)(nil)
53

54
// newTowerListIterator initializes a new towerListIterator from a variadic list
55
// of lnwire.NetAddresses.
56
func newTowerListIterator(candidates ...*Tower) *towerListIterator {
37✔
57
        iter := &towerListIterator{
37✔
58
                queue:      list.New(),
37✔
59
                candidates: make(map[wtdb.TowerID]*Tower),
37✔
60
        }
37✔
61

37✔
62
        for _, candidate := range candidates {
41✔
63
                iter.queue.PushBack(candidate.ID)
4✔
64
                iter.candidates[candidate.ID] = candidate
4✔
65
        }
4✔
66
        iter.Reset()
37✔
67

37✔
68
        return iter
37✔
69
}
70

71
// Reset clears the iterators state, and makes the address at the front of the
72
// list the next item to be returned..
73
func (t *towerListIterator) Reset() error {
168✔
74
        t.mu.Lock()
168✔
75
        defer t.mu.Unlock()
168✔
76

168✔
77
        // Reset the next candidate to the front of the linked-list.
168✔
78
        t.nextCandidate = t.queue.Front()
168✔
79

168✔
80
        return nil
168✔
81
}
168✔
82

83
// GetTower gets the tower with the given ID from the iterator. If no such tower
84
// is found then ErrTowerNotInIterator is returned.
85
func (t *towerListIterator) GetTower(id wtdb.TowerID) (*Tower, error) {
6✔
86
        t.mu.Lock()
6✔
87
        defer t.mu.Unlock()
6✔
88

6✔
89
        tower, ok := t.candidates[id]
6✔
90
        if !ok {
7✔
91
                return nil, ErrTowerNotInIterator
1✔
92
        }
1✔
93

94
        return tower, nil
5✔
95
}
96

97
// Next returns the next candidate tower. This iterator will always return
98
// candidates in the order given when the iterator was instantiated.  If no more
99
// candidates are available, ErrTowerCandidatesExhausted is returned.
100
func (t *towerListIterator) Next() (*Tower, error) {
251✔
101
        t.mu.Lock()
251✔
102
        defer t.mu.Unlock()
251✔
103

251✔
104
        for t.nextCandidate != nil {
377✔
105
                // Propose the tower at the front of the list.
126✔
106
                towerID := t.nextCandidate.Value.(wtdb.TowerID)
126✔
107

126✔
108
                // Check whether this tower is still considered a candidate. If
126✔
109
                // it's not, we'll proceed to the next.
126✔
110
                tower, ok := t.candidates[towerID]
126✔
111
                if !ok {
132✔
112
                        nextCandidate := t.nextCandidate.Next()
6✔
113
                        t.queue.Remove(t.nextCandidate)
6✔
114
                        t.nextCandidate = nextCandidate
6✔
115
                        continue
6✔
116
                }
117

118
                // Set the next candidate to the subsequent element.
119
                t.nextCandidate = t.nextCandidate.Next()
120✔
120
                return tower, nil
120✔
121
        }
122

123
        return nil, ErrTowerCandidatesExhausted
131✔
124
}
125

126
// AddCandidate adds a new candidate tower to the iterator. If the candidate
127
// already exists, then any new addresses are added to it.
128
func (t *towerListIterator) AddCandidate(candidate *Tower) {
58✔
129
        t.mu.Lock()
58✔
130
        defer t.mu.Unlock()
58✔
131

58✔
132
        if tower, ok := t.candidates[candidate.ID]; !ok {
104✔
133
                t.queue.PushBack(candidate.ID)
46✔
134
                t.candidates[candidate.ID] = candidate
46✔
135

46✔
136
                // If we've reached the end of our queue, then this candidate
46✔
137
                // will become the next.
46✔
138
                if t.nextCandidate == nil {
91✔
139
                        t.nextCandidate = t.queue.Back()
45✔
140
                }
45✔
141
        } else {
12✔
142
                candidate.Addresses.Reset()
12✔
143
                firstAddr := candidate.Addresses.Peek()
12✔
144
                tower.Addresses.Add(firstAddr)
12✔
145
                for {
27✔
146
                        next, err := candidate.Addresses.Next()
15✔
147
                        if err != nil {
27✔
148
                                candidate.Addresses.Reset()
12✔
149
                                break
12✔
150
                        }
151

152
                        tower.Addresses.Add(next)
3✔
153
                }
154
        }
155
}
156

157
// RemoveCandidate removes an existing candidate tower from the iterator. An
158
// optional address can be provided to indicate a stale tower address to remove
159
// it. If it isn't provided, then the tower is completely removed from the
160
// iterator.
161
func (t *towerListIterator) RemoveCandidate(candidate wtdb.TowerID,
162
        addr net.Addr) error {
16✔
163

16✔
164
        t.mu.Lock()
16✔
165
        defer t.mu.Unlock()
16✔
166

16✔
167
        tower, ok := t.candidates[candidate]
16✔
168
        if !ok {
16✔
UNCOV
169
                return nil
×
UNCOV
170
        }
×
171
        if addr != nil {
20✔
172
                err := tower.Addresses.Remove(addr)
4✔
173
                if err != nil {
6✔
174
                        return err
2✔
175
                }
2✔
176
        } else {
12✔
177
                if tower.Addresses.HasLocked() {
12✔
178
                        return ErrAddrInUse
×
179
                }
×
180

181
                delete(t.candidates, candidate)
12✔
182
        }
183

184
        return nil
14✔
185
}
186

187
// IsActive determines whether a given tower is exists within the iterator.
188
func (t *towerListIterator) IsActive(tower wtdb.TowerID) bool {
15✔
189
        t.mu.Lock()
15✔
190
        defer t.mu.Unlock()
15✔
191

15✔
192
        _, ok := t.candidates[tower]
15✔
193
        return ok
15✔
194
}
15✔
195

196
// TODO(conner): implement graph-backed candidate iterator for public towers.
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