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

lightningnetwork / lnd / 13440912774

20 Feb 2025 05:14PM UTC coverage: 57.697% (-1.1%) from 58.802%
13440912774

Pull #9535

github

guggero
GitHub: remove duplicate caching

Turns out that actions/setup-go starting with @v4 also adds caching.
With that, our cache size on disk has almost doubled, leading to the
GitHub runner running out of space in certain situation.
We fix that by disabling the automated caching since we already have our
own, custom-tailored version.
Pull Request #9535: GitHub: remove duplicate caching

103519 of 179417 relevant lines covered (57.7%)

24825.3 hits per line

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

0.0
/watchtower/standalone.go
1
package watchtower
2

3
import (
4
        "net"
5
        "sync/atomic"
6
        "time"
7

8
        "github.com/btcsuite/btcd/btcec/v2"
9
        "github.com/lightningnetwork/lnd/brontide"
10
        "github.com/lightningnetwork/lnd/lnencrypt"
11
        "github.com/lightningnetwork/lnd/tor"
12
        "github.com/lightningnetwork/lnd/watchtower/lookout"
13
        "github.com/lightningnetwork/lnd/watchtower/wtserver"
14
)
15

16
// Standalone encapsulates the server-side functionality required by watchtower
17
// clients. A Standalone couples the two primary subsystems such that, as a
18
// unit, this instance can negotiate sessions with clients, accept state updates
19
// for active sessions, monitor the chain for breaches matching known breach
20
// hints, publish reconstructed justice transactions on behalf of tower clients.
21
type Standalone struct {
22
        started uint32 // to be used atomically
23
        stopped uint32 // to be used atomically
24

25
        cfg *Config
26

27
        // listeners is a reference to the wtserver's listeners.
28
        listeners []net.Listener
29

30
        // server is the client endpoint, used for negotiating sessions and
31
        // uploading state updates.
32
        server wtserver.Interface
33

34
        // lookout is a service that monitors the chain and inspects the
35
        // transactions found in new blocks against the state updates received
36
        // by the server.
37
        lookout lookout.Service
38
}
39

40
// New validates the passed Config and returns a fresh Standalone instance if
41
// the tower's subsystems could be properly initialized.
42
func New(cfg *Config) (*Standalone, error) {
×
43
        // The tower must have listening address in order to accept new updates
×
44
        // from clients.
×
45
        if len(cfg.ListenAddrs) == 0 {
×
46
                return nil, ErrNoListeners
×
47
        }
×
48

49
        // Assign the default read timeout if none is provided.
50
        if cfg.ReadTimeout == 0 {
×
51
                cfg.ReadTimeout = DefaultReadTimeout
×
52
        }
×
53

54
        // Assign the default write timeout if none is provided.
55
        if cfg.WriteTimeout == 0 {
×
56
                cfg.WriteTimeout = DefaultWriteTimeout
×
57
        }
×
58

59
        punisher := lookout.NewBreachPunisher(&lookout.PunisherConfig{
×
60
                PublishTx: cfg.PublishTx,
×
61
        })
×
62

×
63
        // Initialize the lookout service with its required resources.
×
64
        lookout := lookout.New(&lookout.Config{
×
65
                BlockFetcher:   cfg.BlockFetcher,
×
66
                DB:             cfg.DB,
×
67
                EpochRegistrar: cfg.EpochRegistrar,
×
68
                Punisher:       punisher,
×
69
                MinBackoff:     time.Second,
×
70
                MaxBackoff:     time.Minute,
×
71
                MaxNumRetries:  5,
×
72
        })
×
73

×
74
        // Create a brontide listener on each of the provided listening
×
75
        // addresses. Client should be able to connect to any of open ports to
×
76
        // communicate with this Standalone instance.
×
77
        listeners := make([]net.Listener, 0, len(cfg.ListenAddrs))
×
78
        for _, listenAddr := range cfg.ListenAddrs {
×
79
                listener, err := brontide.NewListener(
×
80
                        cfg.NodeKeyECDH, listenAddr.String(),
×
81
                )
×
82
                if err != nil {
×
83
                        return nil, err
×
84
                }
×
85

86
                listeners = append(listeners, listener)
×
87
        }
88

89
        // Initialize the server with its required resources.
90
        server, err := wtserver.New(&wtserver.Config{
×
91
                ChainHash:     cfg.ChainHash,
×
92
                DB:            cfg.DB,
×
93
                NodeKeyECDH:   cfg.NodeKeyECDH,
×
94
                Listeners:     listeners,
×
95
                ReadTimeout:   cfg.ReadTimeout,
×
96
                WriteTimeout:  cfg.WriteTimeout,
×
97
                NewAddress:    cfg.NewAddress,
×
98
                DisableReward: true,
×
99
        })
×
100
        if err != nil {
×
101
                return nil, err
×
102
        }
×
103

104
        return &Standalone{
×
105
                cfg:       cfg,
×
106
                listeners: listeners,
×
107
                server:    server,
×
108
                lookout:   lookout,
×
109
        }, nil
×
110
}
111

112
// Start idempotently starts the Standalone, an error is returned if the
113
// subsystems could not be initialized.
114
func (w *Standalone) Start() error {
×
115
        if !atomic.CompareAndSwapUint32(&w.started, 0, 1) {
×
116
                return nil
×
117
        }
×
118

119
        log.Infof("Starting watchtower")
×
120

×
121
        // If a tor controller exists in the config, then automatically create a
×
122
        // hidden service for the watchtower to accept inbound connections from.
×
123
        if w.cfg.TorController != nil {
×
124
                log.Infof("Creating watchtower hidden service")
×
125
                if err := w.createNewHiddenService(); err != nil {
×
126
                        return err
×
127
                }
×
128
        }
129

130
        if err := w.lookout.Start(); err != nil {
×
131
                return err
×
132
        }
×
133
        if err := w.server.Start(); err != nil {
×
134
                w.lookout.Stop()
×
135
                return err
×
136
        }
×
137

138
        log.Infof("Watchtower started successfully")
×
139

×
140
        return nil
×
141
}
142

143
// Stop idempotently stops the Standalone and blocks until the subsystems have
144
// completed their shutdown.
145
func (w *Standalone) Stop() error {
×
146
        if !atomic.CompareAndSwapUint32(&w.stopped, 0, 1) {
×
147
                return nil
×
148
        }
×
149

150
        log.Infof("Stopping watchtower")
×
151

×
152
        w.server.Stop()
×
153
        w.lookout.Stop()
×
154

×
155
        log.Infof("Watchtower stopped successfully")
×
156

×
157
        return nil
×
158
}
159

160
// createNewHiddenService automatically sets up a v2 or v3 onion service in
161
// order to listen for inbound connections over Tor.
162
func (w *Standalone) createNewHiddenService() error {
×
163
        // Get all the ports the watchtower is listening on. These will be used to
×
164
        // map the hidden service's virtual port.
×
165
        listenPorts := make([]int, 0, len(w.listeners))
×
166
        for _, listener := range w.listeners {
×
167
                port := listener.Addr().(*net.TCPAddr).Port
×
168
                listenPorts = append(listenPorts, port)
×
169
        }
×
170

171
        encrypter, err := lnencrypt.KeyRingEncrypter(w.cfg.KeyRing)
×
172
        if err != nil {
×
173
                return err
×
174
        }
×
175

176
        // Once we've created the port mapping, we can automatically create the
177
        // hidden service. The service's private key will be saved on disk in order
178
        // to persistently have access to this hidden service across restarts.
179
        onionCfg := tor.AddOnionConfig{
×
180
                VirtualPort: DefaultPeerPort,
×
181
                TargetPorts: listenPorts,
×
182
                Store: tor.NewOnionFile(
×
183
                        w.cfg.WatchtowerKeyPath, 0600, w.cfg.EncryptKey,
×
184
                        encrypter,
×
185
                ),
×
186
                Type: w.cfg.Type,
×
187
        }
×
188

×
189
        addr, err := w.cfg.TorController.AddOnion(onionCfg)
×
190
        if err != nil {
×
191
                return err
×
192
        }
×
193

194
        // Append this address to ExternalIPs so that it will be exposed in
195
        // tower info calls.
196
        w.cfg.ExternalIPs = append(w.cfg.ExternalIPs, addr)
×
197

×
198
        return nil
×
199
}
200

201
// PubKey returns the public key for the watchtower used to authentication and
202
// encrypt traffic with clients.
203
//
204
// NOTE: Part of the watchtowerrpc.WatchtowerBackend interface.
205
func (w *Standalone) PubKey() *btcec.PublicKey {
×
206
        return w.cfg.NodeKeyECDH.PubKey()
×
207
}
×
208

209
// ListeningAddrs returns the listening addresses where the watchtower server
210
// can accept client connections.
211
//
212
// NOTE: Part of the watchtowerrpc.WatchtowerBackend interface.
213
func (w *Standalone) ListeningAddrs() []net.Addr {
×
214
        addrs := make([]net.Addr, 0, len(w.listeners))
×
215
        for _, listener := range w.listeners {
×
216
                addrs = append(addrs, listener.Addr())
×
217
        }
×
218

219
        return addrs
×
220
}
221

222
// ExternalIPs returns the addresses where the watchtower can be reached by
223
// clients externally.
224
//
225
// NOTE: Part of the watchtowerrpc.WatchtowerBackend interface.
226
func (w *Standalone) ExternalIPs() []net.Addr {
×
227
        addrs := make([]net.Addr, 0, len(w.cfg.ExternalIPs))
×
228
        addrs = append(addrs, w.cfg.ExternalIPs...)
×
229

×
230
        return addrs
×
231
}
×
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