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

lightningnetwork / lnd / 13408822928

19 Feb 2025 08:59AM UTC coverage: 41.123% (-17.7%) from 58.794%
13408822928

Pull #9521

github

web-flow
Merge d2f397b3c into 0e8786348
Pull Request #9521: unit: remove GOACC, use Go 1.20 native coverage functionality

92496 of 224923 relevant lines covered (41.12%)

18825.83 hits per line

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

0.0
/lnrpc/peersrpc/peers_server.go
1
//go:build peersrpc
2
// +build peersrpc
3

4
package peersrpc
5

6
import (
7
        "context"
8
        "fmt"
9
        "net"
10
        "sync/atomic"
11

12
        "github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
13
        "github.com/lightningnetwork/lnd/feature"
14
        "github.com/lightningnetwork/lnd/lncfg"
15
        "github.com/lightningnetwork/lnd/lnrpc"
16
        "github.com/lightningnetwork/lnd/lnwire"
17
        "github.com/lightningnetwork/lnd/netann"
18
        "google.golang.org/grpc"
19
        "gopkg.in/macaroon-bakery.v2/bakery"
20
)
21

22
const (
23
        // subServerName is the name of the sub rpc server. We'll use this name
24
        // to register ourselves, and we also require that the main
25
        // SubServerConfigDispatcher instance recognize tt as the name of our
26
        // RPC service.
27
        subServerName = "PeersRPC"
28
)
29

30
var (
31
        // macPermissions maps RPC calls to the permissions they require.
32
        macPermissions = map[string][]bakery.Op{
33
                "/peersrpc.Peers/UpdateNodeAnnouncement": {{
34
                        Entity: "peers",
35
                        Action: "write",
36
                }},
37
        }
38
)
39

40
// ServerShell is a shell struct holding a reference to the actual sub-server.
41
// It is used to register the gRPC sub-server with the root server before we
42
// have the necessary dependencies to populate the actual sub-server.
43
type ServerShell struct {
44
        PeersServer
45
}
46

47
// Server is a sub-server of the main RPC server: the peers RPC. This sub
48
// RPC server allows to intereact with our Peers in the Lightning Network.
49
type Server struct {
50
        started  int32 // To be used atomically.
51
        shutdown int32 // To be used atomically.
52

53
        // Required by the grpc-gateway/v2 library for forward compatibility.
54
        // Must be after the atomically used variables to not break struct
55
        // alignment.
56
        UnimplementedPeersServer
57

58
        cfg *Config
59
}
60

61
// A compile time check to ensure that Server fully implements the PeersServer
62
// gRPC service.
63
var _ PeersServer = (*Server)(nil)
64

65
// New returns a new instance of the peersrpc Peers sub-server. We also
66
// return the set of permissions for the macaroons that we may create within
67
// this method. If the macaroons we need aren't found in the filepath, then
68
// we'll create them on start up. If we're unable to locate, or create the
69
// macaroons we need, then we'll return with an error.
70
func New(cfg *Config) (*Server, lnrpc.MacaroonPerms, error) {
×
71
        server := &Server{
×
72
                cfg: cfg,
×
73
        }
×
74

×
75
        return server, macPermissions, nil
×
76
}
×
77

78
// Start launches any helper goroutines required for the Server to function.
79
//
80
// NOTE: This is part of the lnrpc.SubServer interface.
81
func (s *Server) Start() error {
×
82
        if atomic.AddInt32(&s.started, 1) != 1 {
×
83
                return nil
×
84
        }
×
85

86
        return nil
×
87
}
88

89
// Stop signals any active goroutines for a graceful closure.
90
//
91
// NOTE: This is part of the lnrpc.SubServer interface.
92
func (s *Server) Stop() error {
×
93
        if atomic.AddInt32(&s.shutdown, 1) != 1 {
×
94
                return nil
×
95
        }
×
96

97
        return nil
×
98
}
99

100
// Name returns a unique string representation of the sub-server. This can be
101
// used to identify the sub-server and also de-duplicate them.
102
//
103
// NOTE: This is part of the lnrpc.SubServer interface.
104
func (s *Server) Name() string {
×
105
        return subServerName
×
106
}
×
107

108
// RegisterWithRootServer will be called by the root gRPC server to direct a
109
// sub RPC server to register itself with the main gRPC root server. Until this
110
// is called, each sub-server won't be able to have
111
// requests routed towards it.
112
//
113
// NOTE: This is part of the lnrpc.GrpcHandler interface.
114
func (r *ServerShell) RegisterWithRootServer(grpcServer *grpc.Server) error {
×
115
        // We make sure that we register it with the main gRPC server to ensure
×
116
        // all our methods are routed properly.
×
117
        RegisterPeersServer(grpcServer, r)
×
118

×
119
        log.Debugf("Peers RPC server successfully registered with root " +
×
120
                "gRPC server")
×
121

×
122
        return nil
×
123
}
×
124

125
// RegisterWithRestServer will be called by the root REST mux to direct a sub
126
// RPC server to register itself with the main REST mux server. Until this is
127
// called, each sub-server won't be able to have requests routed towards it.
128
//
129
// NOTE: This is part of the lnrpc.GrpcHandler interface.
130
func (r *ServerShell) RegisterWithRestServer(ctx context.Context,
131
        mux *runtime.ServeMux, dest string, opts []grpc.DialOption) error {
×
132

×
133
        // We make sure that we register it with the main REST server to ensure
×
134
        // all our methods are routed properly.
×
135
        err := RegisterPeersHandlerFromEndpoint(ctx, mux, dest, opts)
×
136
        if err != nil {
×
137
                log.Errorf("Could not register Peers REST server "+
×
138
                        "with root REST server: %v", err)
×
139
                return err
×
140
        }
×
141

142
        log.Debugf("Peers REST server successfully registered with " +
×
143
                "root REST server")
×
144
        return nil
×
145
}
146

147
// CreateSubServer populates the subserver's dependencies using the passed
148
// SubServerConfigDispatcher. This method should fully initialize the
149
// sub-server instance, making it ready for action. It returns the macaroon
150
// permissions that the sub-server wishes to pass on to the root server for all
151
// methods routed towards it.
152
//
153
// NOTE: This is part of the lnrpc.GrpcHandler interface.
154
func (r *ServerShell) CreateSubServer(configRegistry lnrpc.SubServerConfigDispatcher) (
155
        lnrpc.SubServer, lnrpc.MacaroonPerms, error) {
×
156

×
157
        subServer, macPermissions, err := createNewSubServer(configRegistry)
×
158
        if err != nil {
×
159
                return nil, nil, err
×
160
        }
×
161

162
        r.PeersServer = subServer
×
163
        return subServer, macPermissions, nil
×
164
}
165

166
// updateAddresses computes the new address set after executing the update
167
// actions.
168
func (s *Server) updateAddresses(currentAddresses []net.Addr,
169
        updates []*UpdateAddressAction) ([]net.Addr, *lnrpc.Op, error) {
×
170

×
171
        // net.Addr is not comparable so we cannot use the default map
×
172
        // (map[net.Addr]struct{}) so we have to use arrays and a helping
×
173
        // function.
×
174
        findAddr := func(addr net.Addr, slice []net.Addr) bool {
×
175
                for _, sAddr := range slice {
×
176
                        if sAddr.Network() != addr.Network() {
×
177
                                continue
×
178
                        }
179

180
                        if sAddr.String() == addr.String() {
×
181
                                return true
×
182
                        }
×
183
                }
184
                return false
×
185
        }
186

187
        // Preallocate enough memory for both arrays.
188
        removeAddr := make([]net.Addr, 0, len(updates))
×
189
        addAddr := make([]net.Addr, 0, len(updates))
×
190
        for _, update := range updates {
×
191
                addr, err := s.cfg.ParseAddr(update.Address)
×
192
                if err != nil {
×
193
                        return nil, nil, fmt.Errorf("unable to resolve "+
×
194
                                "address %v: %v", update.Address, err)
×
195
                }
×
196

197
                switch update.Action {
×
198
                case UpdateAction_ADD:
×
199
                        addAddr = append(addAddr, addr)
×
200
                case UpdateAction_REMOVE:
×
201
                        removeAddr = append(removeAddr, addr)
×
202
                default:
×
203
                        return nil, nil, fmt.Errorf("invalid address update "+
×
204
                                "action: %v", update.Action)
×
205
                }
206
        }
207

208
        // Look for any inconsistency trying to add AND remove the same address.
209
        for _, addr := range removeAddr {
×
210
                if findAddr(addr, addAddr) {
×
211
                        return nil, nil, fmt.Errorf("invalid updates for "+
×
212
                                "removing AND adding %v", addr)
×
213
                }
×
214
        }
215

216
        ops := &lnrpc.Op{Entity: "addresses"}
×
217
        newAddrs := make([]net.Addr, 0, len(updates)+len(currentAddresses))
×
218

×
219
        // Copy current addresses excluding the ones that need to be removed.
×
220
        for _, addr := range currentAddresses {
×
221
                if findAddr(addr, removeAddr) {
×
222
                        ops.Actions = append(
×
223
                                ops.Actions,
×
224
                                fmt.Sprintf("%s removed", addr.String()),
×
225
                        )
×
226
                        continue
×
227
                }
228
                newAddrs = append(newAddrs, addr)
×
229
        }
230

231
        // Add new adresses if needed.
232
        for _, addr := range addAddr {
×
233
                if !findAddr(addr, newAddrs) {
×
234
                        ops.Actions = append(
×
235
                                ops.Actions,
×
236
                                fmt.Sprintf("%s added", addr.String()),
×
237
                        )
×
238
                        newAddrs = append(newAddrs, addr)
×
239
                }
×
240
        }
241

242
        return newAddrs, ops, nil
×
243
}
244

245
// updateFeatures computes the new raw SetNodeAnn after executing the update
246
// actions.
247
func (s *Server) updateFeatures(currentfeatures *lnwire.RawFeatureVector,
248
        updates []*UpdateFeatureAction) (*lnwire.RawFeatureVector,
249
        *lnrpc.Op, error) {
×
250

×
251
        ops := &lnrpc.Op{Entity: "features"}
×
252
        raw := currentfeatures.Clone()
×
253

×
254
        for _, update := range updates {
×
255
                bit := lnwire.FeatureBit(update.FeatureBit)
×
256

×
257
                switch update.Action {
×
258
                case UpdateAction_ADD:
×
259
                        if raw.IsSet(bit) {
×
260
                                return nil, nil, fmt.Errorf(
×
261
                                        "invalid add action for bit %v, "+
×
262
                                                "bit is already set",
×
263
                                        update.FeatureBit,
×
264
                                )
×
265
                        }
×
266
                        raw.Set(bit)
×
267
                        ops.Actions = append(
×
268
                                ops.Actions,
×
269
                                fmt.Sprintf("%s set", lnwire.Features[bit]),
×
270
                        )
×
271

272
                case UpdateAction_REMOVE:
×
273
                        if !raw.IsSet(bit) {
×
274
                                return nil, nil, fmt.Errorf(
×
275
                                        "invalid remove action for bit %v, "+
×
276
                                                "bit is already unset",
×
277
                                        update.FeatureBit,
×
278
                                )
×
279
                        }
×
280
                        raw.Unset(bit)
×
281
                        ops.Actions = append(
×
282
                                ops.Actions,
×
283
                                fmt.Sprintf("%s unset", lnwire.Features[bit]),
×
284
                        )
×
285

286
                default:
×
287
                        return nil, nil, fmt.Errorf(
×
288
                                "invalid update action (%v) for bit %v",
×
289
                                update.Action,
×
290
                                update.FeatureBit,
×
291
                        )
×
292
                }
293
        }
294

295
        // Validate our new SetNodeAnn.
296
        fv := lnwire.NewFeatureVector(raw, lnwire.Features)
×
297
        if err := feature.ValidateDeps(fv); err != nil {
×
298
                return nil, nil, fmt.Errorf(
×
299
                        "invalid feature set (SetNodeAnn): %v",
×
300
                        err,
×
301
                )
×
302
        }
×
303

304
        return raw, ops, nil
×
305
}
306

307
// UpdateNodeAnnouncement allows the caller to update the node parameters
308
// and broadcasts a new version of the node announcement to its peers.
309
func (s *Server) UpdateNodeAnnouncement(_ context.Context,
310
        req *NodeAnnouncementUpdateRequest) (
311
        *NodeAnnouncementUpdateResponse, error) {
×
312

×
313
        resp := &NodeAnnouncementUpdateResponse{}
×
314
        nodeModifiers := make([]netann.NodeAnnModifier, 0)
×
315

×
316
        currentNodeAnn := s.cfg.GetNodeAnnouncement()
×
317

×
318
        nodeAnnFeatures := currentNodeAnn.Features
×
319
        featureUpdates := len(req.FeatureUpdates) > 0
×
320
        if featureUpdates {
×
321
                var (
×
322
                        ops *lnrpc.Op
×
323
                        err error
×
324
                )
×
325
                nodeAnnFeatures, ops, err = s.updateFeatures(
×
326
                        nodeAnnFeatures, req.FeatureUpdates,
×
327
                )
×
328
                if err != nil {
×
329
                        return nil, fmt.Errorf("error trying to update node "+
×
330
                                "features: %w", err)
×
331
                }
×
332
                resp.Ops = append(resp.Ops, ops)
×
333
        }
334

335
        if req.Color != "" {
×
336
                color, err := lncfg.ParseHexColor(req.Color)
×
337
                if err != nil {
×
338
                        return nil, fmt.Errorf("unable to parse color: %w", err)
×
339
                }
×
340

341
                if color != currentNodeAnn.RGBColor {
×
342
                        resp.Ops = append(resp.Ops, &lnrpc.Op{
×
343
                                Entity: "color",
×
344
                                Actions: []string{
×
345
                                        fmt.Sprintf("changed to %v", color),
×
346
                                },
×
347
                        })
×
348
                        nodeModifiers = append(
×
349
                                nodeModifiers,
×
350
                                netann.NodeAnnSetColor(color),
×
351
                        )
×
352
                }
×
353
        }
354

355
        if req.Alias != "" {
×
356
                alias, err := lnwire.NewNodeAlias(req.Alias)
×
357
                if err != nil {
×
358
                        return nil, fmt.Errorf("invalid alias value: %w", err)
×
359
                }
×
360
                if alias != currentNodeAnn.Alias {
×
361
                        resp.Ops = append(resp.Ops, &lnrpc.Op{
×
362
                                Entity: "alias",
×
363
                                Actions: []string{
×
364
                                        fmt.Sprintf("changed to %v", alias),
×
365
                                },
×
366
                        })
×
367
                        nodeModifiers = append(
×
368
                                nodeModifiers,
×
369
                                netann.NodeAnnSetAlias(alias),
×
370
                        )
×
371
                }
×
372
        }
373

374
        if len(req.AddressUpdates) > 0 {
×
375
                newAddrs, ops, err := s.updateAddresses(
×
376
                        currentNodeAnn.Addresses,
×
377
                        req.AddressUpdates,
×
378
                )
×
379
                if err != nil {
×
380
                        return nil, fmt.Errorf("error trying to update node "+
×
381
                                "addresses: %w", err)
×
382
                }
×
383
                resp.Ops = append(resp.Ops, ops)
×
384
                nodeModifiers = append(
×
385
                        nodeModifiers,
×
386
                        netann.NodeAnnSetAddrs(newAddrs),
×
387
                )
×
388
        }
389

390
        if len(nodeModifiers) == 0 && !featureUpdates {
×
391
                return nil, fmt.Errorf("unable to detect any new values to " +
×
392
                        "update the node announcement")
×
393
        }
×
394

395
        if err := s.cfg.UpdateNodeAnnouncement(
×
396
                nodeAnnFeatures, nodeModifiers...,
×
397
        ); err != nil {
×
398
                return nil, err
×
399
        }
×
400

401
        return resp, nil
×
402
}
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