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

lightningnetwork / lnd / 14000719599

21 Mar 2025 08:54PM UTC coverage: 58.717% (-10.3%) from 68.989%
14000719599

Pull #8754

github

web-flow
Merge 29f363f18 into 5235f3b24
Pull Request #8754: Add `Outbound` Remote Signer implementation

1562 of 2088 new or added lines in 41 files covered. (74.81%)

28126 existing lines in 464 files now uncovered.

97953 of 166822 relevant lines covered (58.72%)

1.82 hits per line

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

83.54
/lnrpc/watchtowerrpc/handler.go
1
//go:build watchtowerrpc
2
// +build watchtowerrpc
3

4
package watchtowerrpc
5

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

12
        "github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
13
        "github.com/lightningnetwork/lnd/lnrpc"
14
        "google.golang.org/grpc"
15
        "gopkg.in/macaroon-bakery.v2/bakery"
16
)
17

18
const (
19
        // subServerName is the name of the sub rpc server. We'll use this name
20
        // to register ourselves, and we also require that the main
21
        // SubServerConfigDispatcher instance recognizes it as the name of our
22
        // RPC service.
23
        subServerName = "WatchtowerRPC"
24
)
25

26
var (
27
        // macPermissions maps RPC calls to the permissions they require.
28
        macPermissions = map[string][]bakery.Op{
29
                "/watchtowerrpc.Watchtower/GetInfo": {{
30
                        Entity: "info",
31
                        Action: "read",
32
                }},
33
        }
34

35
        // ErrTowerNotActive signals that RPC calls cannot be processed because
36
        // the watchtower is not active.
37
        ErrTowerNotActive = errors.New("watchtower not active")
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
        WatchtowerServer
45
}
46

47
// Handler is the RPC server we'll use to interact with the backing active
48
// watchtower.
49
type Handler struct {
50
        injected int32 // To be used atomically.
51

52
        // Required by the grpc-gateway/v2 library for forward compatibility.
53
        UnimplementedWatchtowerServer
54

55
        cfg Config
56
}
57

58
// A compile time check to ensure that Handler fully implements the Handler gRPC
59
// service.
60
var _ WatchtowerServer = (*Handler)(nil)
61

62
// New returns a new instance of the Watchtower sub-server. We also return the
63
// set of permissions for the macaroons that we may create within this method.
64
// If the macaroons we need aren't found in the filepath, then we'll create them
65
// on start up. If we're unable to locate, or create the macaroons we need, then
66
// we'll return with an error.
67
func New() (*Handler, lnrpc.MacaroonPerms, error) {
3✔
68
        return &Handler{cfg: Config{}}, macPermissions, nil
3✔
69
}
3✔
70

71
// Stop signals any active goroutines for a graceful closure.
72
//
73
// NOTE: This is part of the lnrpc.SubServer interface.
74
func (c *Handler) Stop() error {
3✔
75
        return nil
3✔
76
}
3✔
77

78
// InjectDependencies populates the sub-server's dependencies. If the
79
// finalizeDependencies boolean is true, then the sub-server will finalize its
80
// dependencies and return an error if any required dependencies are missing.
81
//
82
// NOTE: This is part of the lnrpc.SubServer interface.
83
func (c *Handler) InjectDependencies(
84
        configRegistry lnrpc.SubServerConfigDispatcher,
85
        finalizeDependencies bool) error {
3✔
86

3✔
87
        if finalizeDependencies && atomic.AddInt32(&c.injected, 1) != 1 {
3✔
NEW
88
                return lnrpc.ErrDependenciesFinalized
×
NEW
89
        }
×
90

91
        cfg, err := getConfig(configRegistry, finalizeDependencies)
3✔
92
        if err != nil {
3✔
NEW
93
                return err
×
NEW
94
        }
×
95

96
        c.cfg = *cfg
3✔
97

3✔
98
        return nil
3✔
99
}
100

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

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

3✔
119
        log.Debugf("Watchtower RPC server successfully registered with root " +
3✔
120
                "gRPC server")
3✔
121

3✔
122
        return nil
3✔
123
}
3✔
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 {
3✔
132

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

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

147
// CreateSubServer creates an instance of the sub-server, and returns the
148
// macaroon permissions that the sub-server wishes to pass on to the root server
149
// for all methods routed towards it.
150
//
151
// NOTE: This is part of the lnrpc.GrpcHandler interface.
152
func (r *ServerShell) CreateSubServer() (
153
        lnrpc.SubServer, lnrpc.MacaroonPerms, error) {
3✔
154

3✔
155
        subServer, macPermissions, err := New()
3✔
156
        if err != nil {
3✔
157
                return nil, nil, err
×
158
        }
×
159

160
        r.WatchtowerServer = subServer
3✔
161
        return subServer, macPermissions, nil
3✔
162
}
163

164
// GetInfo returns information about the Lightning node that this Handler
165
// instance represents. This information includes the node's public key, a list
166
// of network addresses that the tower is listening on, and a list of URIs that
167
// the node is reachable at.
168
func (c *Handler) GetInfo(ctx context.Context,
169
        req *GetInfoRequest) (*GetInfoResponse, error) {
3✔
170

3✔
171
        // Check if the node is active.
3✔
172
        if err := c.isActive(); err != nil {
3✔
173
                return nil, err
×
174
        }
×
175

176
        // Retrieve the node's public key.
177
        pubkey := c.cfg.Tower.PubKey().SerializeCompressed()
3✔
178

3✔
179
        // Retrieve a list of network addresses that the tower is listening on.
3✔
180
        var listeners []string
3✔
181
        for _, addr := range c.cfg.Tower.ListeningAddrs() {
6✔
182
                listeners = append(listeners, addr.String())
3✔
183
        }
3✔
184

185
        // Retrieve a list of external IP addresses that the node is reachable
186
        // at.
187
        var uris []string
3✔
188
        for _, addr := range c.cfg.Tower.ExternalIPs() {
6✔
189
                uris = append(uris, fmt.Sprintf("%x@%v", pubkey, addr))
3✔
190
        }
3✔
191

192
        return &GetInfoResponse{
3✔
193
                Pubkey:    pubkey,
3✔
194
                Listeners: listeners,
3✔
195
                Uris:      uris,
3✔
196
        }, nil
3✔
197
}
198

199
// isActive returns nil if the tower backend is initialized, and the Handler can
200
// process RPC requests.
201
func (c *Handler) isActive() error {
3✔
202
        if c.cfg.Active {
6✔
203
                return nil
3✔
204
        }
3✔
205
        return ErrTowerNotActive
×
206
}
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