forked from lightningnetwork/lnd
-
Notifications
You must be signed in to change notification settings - Fork 2
/
subrpcserver_config.go
319 lines (277 loc) · 10.5 KB
/
subrpcserver_config.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
package lnd
import (
"fmt"
"reflect"
"github.com/btcsuite/btcd/chaincfg"
"github.com/btcsuite/btclog"
"github.com/lightningnetwork/lnd/autopilot"
"github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/htlcswitch"
"github.com/lightningnetwork/lnd/invoices"
"github.com/lightningnetwork/lnd/lncfg"
"github.com/lightningnetwork/lnd/lnrpc/autopilotrpc"
"github.com/lightningnetwork/lnd/lnrpc/chainrpc"
"github.com/lightningnetwork/lnd/lnrpc/invoicesrpc"
"github.com/lightningnetwork/lnd/lnrpc/routerrpc"
"github.com/lightningnetwork/lnd/lnrpc/signrpc"
"github.com/lightningnetwork/lnd/lnrpc/walletrpc"
"github.com/lightningnetwork/lnd/lnrpc/watchtowerrpc"
"github.com/lightningnetwork/lnd/lnrpc/wtclientrpc"
"github.com/lightningnetwork/lnd/lnwire"
"github.com/lightningnetwork/lnd/macaroons"
"github.com/lightningnetwork/lnd/netann"
"github.com/lightningnetwork/lnd/routing"
"github.com/lightningnetwork/lnd/sweep"
"github.com/lightningnetwork/lnd/watchtower"
"github.com/lightningnetwork/lnd/watchtower/wtclient"
)
// subRPCServerConfigs is special sub-config in the main configuration that
// houses the configuration for the optional sub-servers. These sub-RPC servers
// are meant to house experimental new features that may eventually make it
// into the main RPC server that lnd exposes. Special methods are present on
// this struct to allow the main RPC server to create and manipulate the
// sub-RPC servers in a generalized manner.
type subRPCServerConfigs struct {
// SignRPC is a sub-RPC server that exposes signing of arbitrary inputs
// as a gRPC service.
SignRPC *signrpc.Config `group:"signrpc" namespace:"signrpc"`
// WalletKitRPC is a sub-RPC server that exposes functionality allowing
// a client to send transactions through a wallet, publish them, and
// also requests keys and addresses under control of the backing
// wallet.
WalletKitRPC *walletrpc.Config `group:"walletrpc" namespace:"walletrpc"`
// AutopilotRPC is a sub-RPC server that exposes methods on the running
// autopilot as a gRPC service.
AutopilotRPC *autopilotrpc.Config `group:"autopilotrpc" namespace:"autopilotrpc"`
// ChainRPC is a sub-RPC server that exposes functionality allowing a
// client to be notified of certain on-chain events (new blocks,
// confirmations, spends).
ChainRPC *chainrpc.Config `group:"chainrpc" namespace:"chainrpc"`
// InvoicesRPC is a sub-RPC server that exposes invoice related methods
// as a gRPC service.
InvoicesRPC *invoicesrpc.Config `group:"invoicesrpc" namespace:"invoicesrpc"`
// RouterRPC is a sub-RPC server the exposes functionality that allows
// clients to send payments on the network, and perform Lightning
// payment related queries such as requests for estimates of off-chain
// fees.
RouterRPC *routerrpc.Config `group:"routerrpc" namespace:"routerrpc"`
// WatchtowerRPC is a sub-RPC server that exposes functionality allowing
// clients to monitor and control their embedded watchtower.
WatchtowerRPC *watchtowerrpc.Config `group:"watchtowerrpc" namespace:"watchtowerrpc"`
// WatchtowerClientRPC is a sub-RPC server that exposes functionality
// that allows clients to interact with the active watchtower client
// instance within lnd in order to add, remove, list registered client
// towers, etc.
WatchtowerClientRPC *wtclientrpc.Config `group:"wtclientrpc" namespace:"wtclientrpc"`
}
// PopulateDependencies attempts to iterate through all the sub-server configs
// within this struct, and populate the items it requires based on the main
// configuration file, and the chain control.
//
// NOTE: This MUST be called before any callers are permitted to execute the
// FetchConfig method.
func (s *subRPCServerConfigs) PopulateDependencies(cfg *Config, cc *chainControl,
networkDir string, macService *macaroons.Service,
atpl *autopilot.Manager,
invoiceRegistry *invoices.InvoiceRegistry,
htlcSwitch *htlcswitch.Switch,
activeNetParams *chaincfg.Params,
chanRouter *routing.ChannelRouter,
routerBackend *routerrpc.RouterBackend,
nodeSigner *netann.NodeSigner,
chanDB *channeldb.DB,
sweeper *sweep.UtxoSweeper,
tower *watchtower.Standalone,
towerClient wtclient.Client,
tcpResolver lncfg.TCPResolver,
genInvoiceFeatures func() *lnwire.FeatureVector,
rpcLogger btclog.Logger) error {
// First, we'll use reflect to obtain a version of the config struct
// that allows us to programmatically inspect its fields.
selfVal := extractReflectValue(s)
selfType := selfVal.Type()
numFields := selfVal.NumField()
for i := 0; i < numFields; i++ {
field := selfVal.Field(i)
fieldElem := field.Elem()
fieldName := selfType.Field(i).Name
ltndLog.Debugf("Populating dependencies for sub RPC "+
"server: %v", fieldName)
// If this sub-config doesn't actually have any fields, then we
// can skip it, as the build tag for it is likely off.
if fieldElem.NumField() == 0 {
continue
}
if !fieldElem.CanSet() {
continue
}
switch subCfg := field.Interface().(type) {
case *signrpc.Config:
subCfgValue := extractReflectValue(subCfg)
subCfgValue.FieldByName("MacService").Set(
reflect.ValueOf(macService),
)
subCfgValue.FieldByName("NetworkDir").Set(
reflect.ValueOf(networkDir),
)
subCfgValue.FieldByName("Signer").Set(
reflect.ValueOf(cc.signer),
)
subCfgValue.FieldByName("KeyRing").Set(
reflect.ValueOf(cc.keyRing),
)
case *walletrpc.Config:
subCfgValue := extractReflectValue(subCfg)
subCfgValue.FieldByName("NetworkDir").Set(
reflect.ValueOf(networkDir),
)
subCfgValue.FieldByName("MacService").Set(
reflect.ValueOf(macService),
)
subCfgValue.FieldByName("FeeEstimator").Set(
reflect.ValueOf(cc.feeEstimator),
)
subCfgValue.FieldByName("Wallet").Set(
reflect.ValueOf(cc.wallet),
)
subCfgValue.FieldByName("KeyRing").Set(
reflect.ValueOf(cc.keyRing),
)
subCfgValue.FieldByName("Sweeper").Set(
reflect.ValueOf(sweeper),
)
subCfgValue.FieldByName("Chain").Set(
reflect.ValueOf(cc.chainIO),
)
case *autopilotrpc.Config:
subCfgValue := extractReflectValue(subCfg)
subCfgValue.FieldByName("Manager").Set(
reflect.ValueOf(atpl),
)
case *chainrpc.Config:
subCfgValue := extractReflectValue(subCfg)
subCfgValue.FieldByName("NetworkDir").Set(
reflect.ValueOf(networkDir),
)
subCfgValue.FieldByName("MacService").Set(
reflect.ValueOf(macService),
)
subCfgValue.FieldByName("ChainNotifier").Set(
reflect.ValueOf(cc.chainNotifier),
)
case *invoicesrpc.Config:
subCfgValue := extractReflectValue(subCfg)
subCfgValue.FieldByName("NetworkDir").Set(
reflect.ValueOf(networkDir),
)
subCfgValue.FieldByName("MacService").Set(
reflect.ValueOf(macService),
)
subCfgValue.FieldByName("InvoiceRegistry").Set(
reflect.ValueOf(invoiceRegistry),
)
subCfgValue.FieldByName("IsChannelActive").Set(
reflect.ValueOf(htlcSwitch.HasActiveLink),
)
subCfgValue.FieldByName("ChainParams").Set(
reflect.ValueOf(activeNetParams),
)
subCfgValue.FieldByName("NodeSigner").Set(
reflect.ValueOf(nodeSigner),
)
defaultDelta := cfg.Bitcoin.TimeLockDelta
if cfg.registeredChains.PrimaryChain() == litecoinChain {
defaultDelta = cfg.Litecoin.TimeLockDelta
}
subCfgValue.FieldByName("DefaultCLTVExpiry").Set(
reflect.ValueOf(defaultDelta),
)
subCfgValue.FieldByName("ChanDB").Set(
reflect.ValueOf(chanDB),
)
subCfgValue.FieldByName("GenInvoiceFeatures").Set(
reflect.ValueOf(genInvoiceFeatures),
)
// RouterRPC isn't conditionally compiled and doesn't need to be
// populated using reflection.
case *routerrpc.Config:
case *watchtowerrpc.Config:
subCfgValue := extractReflectValue(subCfg)
subCfgValue.FieldByName("Active").Set(
reflect.ValueOf(tower != nil),
)
subCfgValue.FieldByName("Tower").Set(
reflect.ValueOf(tower),
)
case *wtclientrpc.Config:
subCfgValue := extractReflectValue(subCfg)
if towerClient != nil {
subCfgValue.FieldByName("Active").Set(
reflect.ValueOf(towerClient != nil),
)
subCfgValue.FieldByName("Client").Set(
reflect.ValueOf(towerClient),
)
}
subCfgValue.FieldByName("Resolver").Set(
reflect.ValueOf(tcpResolver),
)
subCfgValue.FieldByName("Log").Set(
reflect.ValueOf(rpcLogger),
)
default:
return fmt.Errorf("unknown field: %v, %T", fieldName,
cfg)
}
}
// Populate routerrpc dependencies.
s.RouterRPC.NetworkDir = networkDir
s.RouterRPC.MacService = macService
s.RouterRPC.Router = chanRouter
s.RouterRPC.RouterBackend = routerBackend
return nil
}
// FetchConfig attempts to locate an existing configuration file mapped to the
// target sub-server. If we're unable to find a config file matching the
// subServerName name, then false will be returned for the second parameter.
//
// NOTE: Part of the lnrpc.SubServerConfigDispatcher interface.
func (s *subRPCServerConfigs) FetchConfig(subServerName string) (interface{}, bool) {
// First, we'll use reflect to obtain a version of the config struct
// that allows us to programmatically inspect its fields.
selfVal := extractReflectValue(s)
// Now that we have the value of the struct, we can check to see if it
// has an attribute with the same name as the subServerName.
configVal := selfVal.FieldByName(subServerName)
// We'll now ensure that this field actually exists in this value. If
// not, then we'll return false for the ok value to indicate to the
// caller that this field doesn't actually exist.
if !configVal.IsValid() {
return nil, false
}
configValElem := configVal.Elem()
// If a config of this type is found, it doesn't have any fields, then
// it's the same as if it wasn't present. This can happen if the build
// tag for the sub-server is inactive.
if configValElem.NumField() == 0 {
return nil, false
}
// At this pint, we know that the field is actually present in the
// config struct, so we can return it directly.
return configVal.Interface(), true
}
// extractReflectValue attempts to extract the value from an interface using
// the reflect package. The resulting reflect.Value allows the caller to
// programmatically examine and manipulate the underlying value.
func extractReflectValue(instance interface{}) reflect.Value {
var val reflect.Value
// If the type of the instance is a pointer, then we need to deference
// the pointer one level to get its value. Otherwise, we can access the
// value directly.
if reflect.TypeOf(instance).Kind() == reflect.Ptr {
val = reflect.ValueOf(instance).Elem()
} else {
val = reflect.ValueOf(instance)
}
return val
}