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

lightningnetwork / lnd / 13566028875

27 Feb 2025 12:09PM UTC coverage: 49.396% (-9.4%) from 58.748%
13566028875

Pull #9555

github

ellemouton
graph/db: populate the graph cache in Start instead of during construction

In this commit, we move the graph cache population logic out of the
ChannelGraph constructor and into its Start method instead.
Pull Request #9555: graph: extract cache from CRUD [6]

34 of 54 new or added lines in 4 files covered. (62.96%)

27464 existing lines in 436 files now uncovered.

101095 of 204664 relevant lines covered (49.4%)

1.54 hits per line

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

0.0
/netann/host_ann.go
1
package netann
2

3
import (
4
        "net"
5
        "sync"
6

7
        "github.com/lightningnetwork/lnd/lnwire"
8
        "github.com/lightningnetwork/lnd/ticker"
9
)
10

11
// HostAnnouncerConfig is the main config for the HostAnnouncer.
12
type HostAnnouncerConfig struct {
13
        // Hosts is the set of hosts we should watch for IP changes.
14
        Hosts []string
15

16
        // RefreshTicker ticks each time we should check for any address
17
        // changes.
18
        RefreshTicker ticker.Ticker
19

20
        // LookupHost performs DNS resolution on a given host and returns its
21
        // addresses.
22
        LookupHost func(string) (net.Addr, error)
23

24
        // AdvertisedIPs is the set of IPs that we've already announced with
25
        // our current NodeAnnouncement. This set will be constructed to avoid
26
        // unnecessary node NodeAnnouncement updates.
27
        AdvertisedIPs map[string]struct{}
28

29
        // AnnounceNewIPs announces a new set of IP addresses for the backing
30
        // Lightning node. The first set of addresses is the new set of
31
        // addresses that we should advertise, while the other set are the
32
        // stale addresses that we should no longer advertise.
33
        AnnounceNewIPs func([]net.Addr, map[string]struct{}) error
34
}
35

36
// HostAnnouncer is a sub-system that allows a user to specify a set of hosts
37
// for lnd that will be continually resolved to notice any IP address changes.
38
// If the target IP address for a host changes, then we'll generate a new
39
// NodeAnnouncement that includes these new IPs.
40
type HostAnnouncer struct {
41
        cfg HostAnnouncerConfig
42

43
        quit chan struct{}
44
        wg   sync.WaitGroup
45

46
        startOnce sync.Once
47
        stopOnce  sync.Once
48
}
49

50
// NewHostAnnouncer returns a new instance of the HostAnnouncer.
UNCOV
51
func NewHostAnnouncer(cfg HostAnnouncerConfig) *HostAnnouncer {
×
UNCOV
52
        return &HostAnnouncer{
×
UNCOV
53
                cfg:  cfg,
×
UNCOV
54
                quit: make(chan struct{}),
×
UNCOV
55
        }
×
UNCOV
56
}
×
57

58
// Start starts the HostAnnouncer.
UNCOV
59
func (h *HostAnnouncer) Start() error {
×
UNCOV
60
        h.startOnce.Do(func() {
×
UNCOV
61
                log.Info("HostAnnouncer starting")
×
UNCOV
62
                h.wg.Add(1)
×
UNCOV
63
                go h.hostWatcher()
×
UNCOV
64
        })
×
65

UNCOV
66
        return nil
×
67
}
68

69
// Stop signals the HostAnnouncer for a graceful stop.
UNCOV
70
func (h *HostAnnouncer) Stop() error {
×
UNCOV
71
        h.stopOnce.Do(func() {
×
UNCOV
72
                log.Info("HostAnnouncer shutting down...")
×
UNCOV
73
                defer log.Debug("HostAnnouncer shutdown complete")
×
UNCOV
74

×
UNCOV
75
                close(h.quit)
×
UNCOV
76
                h.wg.Wait()
×
UNCOV
77
        })
×
78

UNCOV
79
        return nil
×
80
}
81

82
// hostWatcher periodically attempts to resolve the IP for each host, updating
83
// them if they change within the interval.
UNCOV
84
func (h *HostAnnouncer) hostWatcher() {
×
UNCOV
85
        defer h.wg.Done()
×
UNCOV
86

×
UNCOV
87
        ipMapping := make(map[string]net.Addr)
×
UNCOV
88
        refreshHosts := func() {
×
UNCOV
89
                // We'll now run through each of our hosts to check if they had
×
UNCOV
90
                // their backing IPs changed. If so, we'll want to re-announce
×
UNCOV
91
                // them.
×
UNCOV
92
                var addrsToUpdate []net.Addr
×
UNCOV
93
                addrsToRemove := make(map[string]struct{})
×
UNCOV
94
                for _, host := range h.cfg.Hosts {
×
UNCOV
95
                        newAddr, err := h.cfg.LookupHost(host)
×
UNCOV
96
                        if err != nil {
×
97
                                log.Warnf("unable to resolve IP for "+
×
98
                                        "host %v: %v", host, err)
×
99
                                continue
×
100
                        }
101

102
                        // If nothing has changed since the last time we
103
                        // checked, then we don't need to do any updates.
UNCOV
104
                        oldAddr, oldAddrFound := ipMapping[host]
×
UNCOV
105
                        if oldAddrFound && oldAddr.String() == newAddr.String() {
×
UNCOV
106
                                continue
×
107
                        }
108

109
                        // Update the IP mapping now, as if this is the first
110
                        // time then we don't need to send a new announcement.
UNCOV
111
                        ipMapping[host] = newAddr
×
UNCOV
112

×
UNCOV
113
                        // If this IP has already been announced, then we'll
×
UNCOV
114
                        // skip it to avoid triggering an unnecessary node
×
UNCOV
115
                        // announcement update.
×
UNCOV
116
                        _, ipAnnounced := h.cfg.AdvertisedIPs[newAddr.String()]
×
UNCOV
117
                        if ipAnnounced {
×
UNCOV
118
                                continue
×
119
                        }
120

121
                        // If we've reached this point, then the old address
122
                        // was found, and the new address we just looked up
123
                        // differs from the old one.
UNCOV
124
                        log.Debugf("IP change detected! %v: %v -> %v", host,
×
UNCOV
125
                                oldAddr, newAddr)
×
UNCOV
126

×
UNCOV
127
                        // If we had already advertised an addr for this host,
×
UNCOV
128
                        // then we'll need to remove that old stale address.
×
UNCOV
129
                        if oldAddr != nil {
×
UNCOV
130
                                addrsToRemove[oldAddr.String()] = struct{}{}
×
UNCOV
131
                        }
×
132

UNCOV
133
                        addrsToUpdate = append(addrsToUpdate, newAddr)
×
134
                }
135

136
                // If we don't have any addresses to update, then we can skip
137
                // things around until the next round.
UNCOV
138
                if len(addrsToUpdate) == 0 {
×
UNCOV
139
                        log.Debugf("No IP changes detected for hosts: %v",
×
UNCOV
140
                                h.cfg.Hosts)
×
UNCOV
141
                        return
×
UNCOV
142
                }
×
143

144
                // Now that we know the set of IPs we need to update, we'll do
145
                // them all in a single batch.
UNCOV
146
                err := h.cfg.AnnounceNewIPs(addrsToUpdate, addrsToRemove)
×
UNCOV
147
                if err != nil {
×
148
                        log.Warnf("unable to announce new IPs: %v", err)
×
149
                }
×
150
        }
151

UNCOV
152
        refreshHosts()
×
UNCOV
153

×
UNCOV
154
        h.cfg.RefreshTicker.Resume()
×
UNCOV
155

×
UNCOV
156
        for {
×
UNCOV
157
                select {
×
UNCOV
158
                case <-h.cfg.RefreshTicker.Ticks():
×
UNCOV
159
                        log.Debugf("HostAnnouncer checking for any IP " +
×
UNCOV
160
                                "changes...")
×
UNCOV
161

×
UNCOV
162
                        refreshHosts()
×
163

UNCOV
164
                case <-h.quit:
×
UNCOV
165
                        return
×
166
                }
167
        }
168
}
169

170
// NodeAnnUpdater describes a function that's able to update our current node
171
// announcement on disk. It returns the updated node announcement given a set
172
// of updates to be applied to the current node announcement.
173
type NodeAnnUpdater func(modifier ...NodeAnnModifier,
174
) (lnwire.NodeAnnouncement, error)
175

176
// IPAnnouncer is a factory function that generates a new function that uses
177
// the passed annUpdater function to to announce new IP changes for a given
178
// host.
179
func IPAnnouncer(annUpdater NodeAnnUpdater) func([]net.Addr,
180
        map[string]struct{}) error {
×
181

×
182
        return func(newAddrs []net.Addr, oldAddrs map[string]struct{}) error {
×
183
                _, err := annUpdater(func(
×
184
                        currentNodeAnn *lnwire.NodeAnnouncement) {
×
185
                        // To ensure we don't duplicate any addresses, we'll
×
186
                        // filter out the same of addresses we should no longer
×
187
                        // advertise.
×
188
                        filteredAddrs := make(
×
189
                                []net.Addr, 0, len(currentNodeAnn.Addresses),
×
190
                        )
×
191
                        for _, addr := range currentNodeAnn.Addresses {
×
192
                                if _, ok := oldAddrs[addr.String()]; ok {
×
193
                                        continue
×
194
                                }
195

196
                                filteredAddrs = append(filteredAddrs, addr)
×
197
                        }
198

199
                        filteredAddrs = append(filteredAddrs, newAddrs...)
×
200
                        currentNodeAnn.Addresses = filteredAddrs
×
201
                })
202
                return err
×
203
        }
204
}
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