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

lightningnetwork / lnd / 11216766535

07 Oct 2024 01:37PM UTC coverage: 57.817% (-1.0%) from 58.817%
11216766535

Pull #9148

github

ProofOfKeags
lnwire: remove kickoff feerate from propose/commit
Pull Request #9148: DynComms [2/n]: lnwire: add authenticated wire messages for Dyn*

571 of 879 new or added lines in 16 files covered. (64.96%)

23253 existing lines in 251 files now uncovered.

99022 of 171268 relevant lines covered (57.82%)

38420.67 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

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

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

24
        cfg *Config
25

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

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

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

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

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

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

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

×
UNCOV
62
        // Initialize the lookout service with its required resources.
×
UNCOV
63
        lookout := lookout.New(&lookout.Config{
×
UNCOV
64
                BlockFetcher:   cfg.BlockFetcher,
×
UNCOV
65
                DB:             cfg.DB,
×
UNCOV
66
                EpochRegistrar: cfg.EpochRegistrar,
×
UNCOV
67
                Punisher:       punisher,
×
UNCOV
68
        })
×
UNCOV
69

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

UNCOV
82
                listeners = append(listeners, listener)
×
83
        }
84

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

UNCOV
100
        return &Standalone{
×
UNCOV
101
                cfg:       cfg,
×
UNCOV
102
                listeners: listeners,
×
UNCOV
103
                server:    server,
×
UNCOV
104
                lookout:   lookout,
×
UNCOV
105
        }, nil
×
106
}
107

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

UNCOV
115
        log.Infof("Starting watchtower")
×
UNCOV
116

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

UNCOV
126
        if err := w.lookout.Start(); err != nil {
×
127
                return err
×
128
        }
×
UNCOV
129
        if err := w.server.Start(); err != nil {
×
130
                w.lookout.Stop()
×
131
                return err
×
132
        }
×
133

UNCOV
134
        log.Infof("Watchtower started successfully")
×
UNCOV
135

×
UNCOV
136
        return nil
×
137
}
138

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

UNCOV
146
        log.Infof("Stopping watchtower")
×
UNCOV
147

×
UNCOV
148
        w.server.Stop()
×
UNCOV
149
        w.lookout.Stop()
×
UNCOV
150

×
UNCOV
151
        log.Infof("Watchtower stopped successfully")
×
UNCOV
152

×
UNCOV
153
        return nil
×
154
}
155

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

167
        encrypter, err := lnencrypt.KeyRingEncrypter(w.cfg.KeyRing)
×
168
        if err != nil {
×
169
                return err
×
170
        }
×
171

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

×
185
        addr, err := w.cfg.TorController.AddOnion(onionCfg)
×
186
        if err != nil {
×
187
                return err
×
188
        }
×
189

190
        // Append this address to ExternalIPs so that it will be exposed in
191
        // tower info calls.
192
        w.cfg.ExternalIPs = append(w.cfg.ExternalIPs, addr)
×
193

×
194
        return nil
×
195
}
196

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

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

UNCOV
215
        return addrs
×
216
}
217

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

×
UNCOV
226
        return addrs
×
UNCOV
227
}
×
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