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

lightningnetwork / lnd / 15869455718

25 Jun 2025 06:53AM UTC coverage: 55.806% (-12.2%) from 67.978%
15869455718

Pull #9148

github

web-flow
Merge c64e3a6c3 into 4335d9cfb
Pull Request #9148: DynComms [2/n]: lnwire: add authenticated wire messages for Dyn*

232 of 270 new or added lines in 5 files covered. (85.93%)

23628 existing lines in 289 files now uncovered.

108377 of 194204 relevant lines covered (55.81%)

22552.93 hits per line

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

0.0
/subrpcserver_config.go
1
package lnd
2

3
import (
4
        "context"
5
        "fmt"
6
        "net"
7
        "reflect"
8

9
        "github.com/btcsuite/btcd/chaincfg"
10
        "github.com/btcsuite/btclog/v2"
11
        "github.com/lightningnetwork/lnd/aliasmgr"
12
        "github.com/lightningnetwork/lnd/autopilot"
13
        "github.com/lightningnetwork/lnd/chainreg"
14
        "github.com/lightningnetwork/lnd/channeldb"
15
        "github.com/lightningnetwork/lnd/fn/v2"
16
        graphdb "github.com/lightningnetwork/lnd/graph/db"
17
        "github.com/lightningnetwork/lnd/htlcswitch"
18
        "github.com/lightningnetwork/lnd/invoices"
19
        "github.com/lightningnetwork/lnd/lncfg"
20
        "github.com/lightningnetwork/lnd/lnrpc/autopilotrpc"
21
        "github.com/lightningnetwork/lnd/lnrpc/chainrpc"
22
        "github.com/lightningnetwork/lnd/lnrpc/devrpc"
23
        "github.com/lightningnetwork/lnd/lnrpc/invoicesrpc"
24
        "github.com/lightningnetwork/lnd/lnrpc/neutrinorpc"
25
        "github.com/lightningnetwork/lnd/lnrpc/peersrpc"
26
        "github.com/lightningnetwork/lnd/lnrpc/routerrpc"
27
        "github.com/lightningnetwork/lnd/lnrpc/signrpc"
28
        "github.com/lightningnetwork/lnd/lnrpc/walletrpc"
29
        "github.com/lightningnetwork/lnd/lnrpc/watchtowerrpc"
30
        "github.com/lightningnetwork/lnd/lnrpc/wtclientrpc"
31
        "github.com/lightningnetwork/lnd/lnwire"
32
        "github.com/lightningnetwork/lnd/macaroons"
33
        "github.com/lightningnetwork/lnd/netann"
34
        "github.com/lightningnetwork/lnd/routing"
35
        "github.com/lightningnetwork/lnd/sweep"
36
        "github.com/lightningnetwork/lnd/watchtower"
37
        "github.com/lightningnetwork/lnd/watchtower/wtclient"
38
        "google.golang.org/protobuf/proto"
39
)
40

41
// subRPCServerConfigs is special sub-config in the main configuration that
42
// houses the configuration for the optional sub-servers. These sub-RPC servers
43
// are meant to house experimental new features that may eventually make it
44
// into the main RPC server that lnd exposes. Special methods are present on
45
// this struct to allow the main RPC server to create and manipulate the
46
// sub-RPC servers in a generalized manner.
47
type subRPCServerConfigs struct {
48
        // SignRPC is a sub-RPC server that exposes signing of arbitrary inputs
49
        // as a gRPC service.
50
        SignRPC *signrpc.Config `group:"signrpc" namespace:"signrpc"`
51

52
        // WalletKitRPC is a sub-RPC server that exposes functionality allowing
53
        // a client to send transactions through a wallet, publish them, and
54
        // also requests keys and addresses under control of the backing
55
        // wallet.
56
        WalletKitRPC *walletrpc.Config `group:"walletrpc" namespace:"walletrpc"`
57

58
        // AutopilotRPC is a sub-RPC server that exposes methods on the running
59
        // autopilot as a gRPC service.
60
        AutopilotRPC *autopilotrpc.Config `group:"autopilotrpc" namespace:"autopilotrpc"`
61

62
        // ChainRPC is a sub-RPC server that exposes functionality allowing a
63
        // client to be notified of certain on-chain events (new blocks,
64
        // confirmations, spends).
65
        ChainRPC *chainrpc.Config `group:"chainrpc" namespace:"chainrpc"`
66

67
        // InvoicesRPC is a sub-RPC server that exposes invoice related methods
68
        // as a gRPC service.
69
        InvoicesRPC *invoicesrpc.Config `group:"invoicesrpc" namespace:"invoicesrpc"`
70

71
        // PeersRPC is a sub-RPC server that exposes peer related methods
72
        // as a gRPC service.
73
        PeersRPC *peersrpc.Config `group:"peersrpc" namespace:"peersrpc"`
74

75
        // NeutrinoKitRPC is a sub-RPC server that exposes functionality allowing
76
        // a client to interact with a running neutrino node.
77
        NeutrinoKitRPC *neutrinorpc.Config `group:"neutrinorpc" namespace:"neutrinorpc"`
78

79
        // RouterRPC is a sub-RPC server the exposes functionality that allows
80
        // clients to send payments on the network, and perform Lightning
81
        // payment related queries such as requests for estimates of off-chain
82
        // fees.
83
        RouterRPC *routerrpc.Config `group:"routerrpc" namespace:"routerrpc"`
84

85
        // WatchtowerRPC is a sub-RPC server that exposes functionality allowing
86
        // clients to monitor and control their embedded watchtower.
87
        WatchtowerRPC *watchtowerrpc.Config `group:"watchtowerrpc" namespace:"watchtowerrpc"`
88

89
        // WatchtowerClientRPC is a sub-RPC server that exposes functionality
90
        // that allows clients to interact with the active watchtower client
91
        // instance within lnd in order to add, remove, list registered client
92
        // towers, etc.
93
        WatchtowerClientRPC *wtclientrpc.Config `group:"wtclientrpc" namespace:"wtclientrpc"`
94

95
        // DevRPC is a sub-RPC server that exposes functionality that allows
96
        // developers manipulate LND state that is normally not possible.
97
        // Should only be used for development purposes.
98
        DevRPC *devrpc.Config `group:"devrpc" namespace:"devrpc"`
99
}
100

101
// PopulateDependencies attempts to iterate through all the sub-server configs
102
// within this struct, and populate the items it requires based on the main
103
// configuration file, and the chain control.
104
//
105
// NOTE: This MUST be called before any callers are permitted to execute the
106
// FetchConfig method.
107
func (s *subRPCServerConfigs) PopulateDependencies(cfg *Config,
108
        cc *chainreg.ChainControl,
109
        networkDir string, macService *macaroons.Service,
110
        atpl *autopilot.Manager,
111
        invoiceRegistry *invoices.InvoiceRegistry,
112
        htlcSwitch *htlcswitch.Switch,
113
        activeNetParams *chaincfg.Params,
114
        chanRouter *routing.ChannelRouter,
115
        routerBackend *routerrpc.RouterBackend,
116
        nodeSigner *netann.NodeSigner,
117
        graphDB *graphdb.ChannelGraph,
118
        chanStateDB *channeldb.ChannelStateDB,
119
        sweeper *sweep.UtxoSweeper,
120
        tower *watchtower.Standalone,
121
        towerClientMgr *wtclient.Manager,
122
        tcpResolver lncfg.TCPResolver,
123
        genInvoiceFeatures func() *lnwire.FeatureVector,
124
        genAmpInvoiceFeatures func() *lnwire.FeatureVector,
125
        getNodeAnnouncement func() lnwire.NodeAnnouncement,
126
        updateNodeAnnouncement func(ctx context.Context,
127
                features *lnwire.RawFeatureVector,
128
                modifiers ...netann.NodeAnnModifier) error,
129
        parseAddr func(addr string) (net.Addr, error),
130
        rpcLogger btclog.Logger, aliasMgr *aliasmgr.Manager,
131
        auxDataParser fn.Option[AuxDataParser],
UNCOV
132
        invoiceHtlcModifier *invoices.HtlcModificationInterceptor) error {
×
UNCOV
133

×
UNCOV
134
        // First, we'll use reflect to obtain a version of the config struct
×
UNCOV
135
        // that allows us to programmatically inspect its fields.
×
UNCOV
136
        selfVal := extractReflectValue(s)
×
UNCOV
137
        selfType := selfVal.Type()
×
UNCOV
138

×
UNCOV
139
        numFields := selfVal.NumField()
×
UNCOV
140
        for i := 0; i < numFields; i++ {
×
UNCOV
141
                field := selfVal.Field(i)
×
UNCOV
142
                fieldElem := field.Elem()
×
UNCOV
143
                fieldName := selfType.Field(i).Name
×
UNCOV
144

×
UNCOV
145
                ltndLog.Debugf("Populating dependencies for sub RPC "+
×
UNCOV
146
                        "server: %v", fieldName)
×
UNCOV
147

×
UNCOV
148
                // If this sub-config doesn't actually have any fields, then we
×
UNCOV
149
                // can skip it, as the build tag for it is likely off.
×
UNCOV
150
                if fieldElem.NumField() == 0 {
×
151
                        continue
×
152
                }
UNCOV
153
                if !fieldElem.CanSet() {
×
154
                        continue
×
155
                }
156

UNCOV
157
                switch subCfg := field.Interface().(type) {
×
UNCOV
158
                case *signrpc.Config:
×
UNCOV
159
                        subCfgValue := extractReflectValue(subCfg)
×
UNCOV
160

×
UNCOV
161
                        subCfgValue.FieldByName("MacService").Set(
×
UNCOV
162
                                reflect.ValueOf(macService),
×
UNCOV
163
                        )
×
UNCOV
164
                        subCfgValue.FieldByName("NetworkDir").Set(
×
UNCOV
165
                                reflect.ValueOf(networkDir),
×
UNCOV
166
                        )
×
UNCOV
167
                        subCfgValue.FieldByName("Signer").Set(
×
UNCOV
168
                                reflect.ValueOf(cc.Signer),
×
UNCOV
169
                        )
×
UNCOV
170
                        subCfgValue.FieldByName("KeyRing").Set(
×
UNCOV
171
                                reflect.ValueOf(cc.KeyRing),
×
UNCOV
172
                        )
×
173

UNCOV
174
                case *walletrpc.Config:
×
UNCOV
175
                        subCfgValue := extractReflectValue(subCfg)
×
UNCOV
176

×
UNCOV
177
                        subCfgValue.FieldByName("NetworkDir").Set(
×
UNCOV
178
                                reflect.ValueOf(networkDir),
×
UNCOV
179
                        )
×
UNCOV
180
                        subCfgValue.FieldByName("MacService").Set(
×
UNCOV
181
                                reflect.ValueOf(macService),
×
UNCOV
182
                        )
×
UNCOV
183
                        subCfgValue.FieldByName("FeeEstimator").Set(
×
UNCOV
184
                                reflect.ValueOf(cc.FeeEstimator),
×
UNCOV
185
                        )
×
UNCOV
186
                        subCfgValue.FieldByName("Wallet").Set(
×
UNCOV
187
                                reflect.ValueOf(cc.Wallet),
×
UNCOV
188
                        )
×
UNCOV
189
                        subCfgValue.FieldByName("CoinSelectionLocker").Set(
×
UNCOV
190
                                reflect.ValueOf(cc.Wallet),
×
UNCOV
191
                        )
×
UNCOV
192
                        subCfgValue.FieldByName("KeyRing").Set(
×
UNCOV
193
                                reflect.ValueOf(cc.KeyRing),
×
UNCOV
194
                        )
×
UNCOV
195
                        subCfgValue.FieldByName("Sweeper").Set(
×
UNCOV
196
                                reflect.ValueOf(sweeper),
×
UNCOV
197
                        )
×
UNCOV
198
                        subCfgValue.FieldByName("Chain").Set(
×
UNCOV
199
                                reflect.ValueOf(cc.ChainIO),
×
UNCOV
200
                        )
×
UNCOV
201
                        subCfgValue.FieldByName("ChainParams").Set(
×
UNCOV
202
                                reflect.ValueOf(activeNetParams),
×
UNCOV
203
                        )
×
UNCOV
204
                        subCfgValue.FieldByName("CurrentNumAnchorChans").Set(
×
UNCOV
205
                                reflect.ValueOf(cc.Wallet.CurrentNumAnchorChans),
×
UNCOV
206
                        )
×
UNCOV
207
                        subCfgValue.FieldByName("CoinSelectionStrategy").Set(
×
UNCOV
208
                                reflect.ValueOf(
×
UNCOV
209
                                        cc.Wallet.Cfg.CoinSelectionStrategy,
×
UNCOV
210
                                ),
×
UNCOV
211
                        )
×
UNCOV
212
                        subCfgValue.FieldByName("ChanStateDB").Set(
×
UNCOV
213
                                reflect.ValueOf(chanStateDB),
×
UNCOV
214
                        )
×
215

UNCOV
216
                case *autopilotrpc.Config:
×
UNCOV
217
                        subCfgValue := extractReflectValue(subCfg)
×
UNCOV
218

×
UNCOV
219
                        subCfgValue.FieldByName("Manager").Set(
×
UNCOV
220
                                reflect.ValueOf(atpl),
×
UNCOV
221
                        )
×
222

UNCOV
223
                case *chainrpc.Config:
×
UNCOV
224
                        subCfgValue := extractReflectValue(subCfg)
×
UNCOV
225

×
UNCOV
226
                        subCfgValue.FieldByName("NetworkDir").Set(
×
UNCOV
227
                                reflect.ValueOf(networkDir),
×
UNCOV
228
                        )
×
UNCOV
229
                        subCfgValue.FieldByName("MacService").Set(
×
UNCOV
230
                                reflect.ValueOf(macService),
×
UNCOV
231
                        )
×
UNCOV
232
                        subCfgValue.FieldByName("ChainNotifier").Set(
×
UNCOV
233
                                reflect.ValueOf(cc.ChainNotifier),
×
UNCOV
234
                        )
×
UNCOV
235
                        subCfgValue.FieldByName("Chain").Set(
×
UNCOV
236
                                reflect.ValueOf(cc.ChainIO),
×
UNCOV
237
                        )
×
238

UNCOV
239
                case *invoicesrpc.Config:
×
UNCOV
240
                        subCfgValue := extractReflectValue(subCfg)
×
UNCOV
241

×
UNCOV
242
                        subCfgValue.FieldByName("NetworkDir").Set(
×
UNCOV
243
                                reflect.ValueOf(networkDir),
×
UNCOV
244
                        )
×
UNCOV
245
                        subCfgValue.FieldByName("MacService").Set(
×
UNCOV
246
                                reflect.ValueOf(macService),
×
UNCOV
247
                        )
×
UNCOV
248
                        subCfgValue.FieldByName("InvoiceRegistry").Set(
×
UNCOV
249
                                reflect.ValueOf(invoiceRegistry),
×
UNCOV
250
                        )
×
UNCOV
251
                        subCfgValue.FieldByName("HtlcModifier").Set(
×
UNCOV
252
                                reflect.ValueOf(invoiceHtlcModifier),
×
UNCOV
253
                        )
×
UNCOV
254
                        subCfgValue.FieldByName("IsChannelActive").Set(
×
UNCOV
255
                                reflect.ValueOf(htlcSwitch.HasActiveLink),
×
UNCOV
256
                        )
×
UNCOV
257
                        subCfgValue.FieldByName("ChainParams").Set(
×
UNCOV
258
                                reflect.ValueOf(activeNetParams),
×
UNCOV
259
                        )
×
UNCOV
260
                        subCfgValue.FieldByName("NodeSigner").Set(
×
UNCOV
261
                                reflect.ValueOf(nodeSigner),
×
UNCOV
262
                        )
×
UNCOV
263
                        defaultDelta := cfg.Bitcoin.TimeLockDelta
×
UNCOV
264
                        subCfgValue.FieldByName("DefaultCLTVExpiry").Set(
×
UNCOV
265
                                reflect.ValueOf(defaultDelta),
×
UNCOV
266
                        )
×
UNCOV
267
                        subCfgValue.FieldByName("Graph").Set(
×
UNCOV
268
                                reflect.ValueOf(graphDB),
×
UNCOV
269
                        )
×
UNCOV
270
                        subCfgValue.FieldByName("ChanStateDB").Set(
×
UNCOV
271
                                reflect.ValueOf(chanStateDB),
×
UNCOV
272
                        )
×
UNCOV
273
                        subCfgValue.FieldByName("GenInvoiceFeatures").Set(
×
UNCOV
274
                                reflect.ValueOf(genInvoiceFeatures),
×
UNCOV
275
                        )
×
UNCOV
276
                        subCfgValue.FieldByName("GenAmpInvoiceFeatures").Set(
×
UNCOV
277
                                reflect.ValueOf(genAmpInvoiceFeatures),
×
UNCOV
278
                        )
×
UNCOV
279
                        subCfgValue.FieldByName("GetAlias").Set(
×
UNCOV
280
                                reflect.ValueOf(aliasMgr.GetPeerAlias),
×
UNCOV
281
                        )
×
UNCOV
282

×
UNCOV
283
                        parseAuxData := func(m proto.Message) error {
×
UNCOV
284
                                return fn.MapOptionZ(
×
UNCOV
285
                                        auxDataParser,
×
UNCOV
286
                                        func(p AuxDataParser) error {
×
287
                                                return p.InlineParseCustomData(
×
288
                                                        m,
×
289
                                                )
×
290
                                        },
×
291
                                )
292
                        }
UNCOV
293
                        subCfgValue.FieldByName("ParseAuxData").Set(
×
UNCOV
294
                                reflect.ValueOf(parseAuxData),
×
UNCOV
295
                        )
×
296

UNCOV
297
                case *neutrinorpc.Config:
×
UNCOV
298
                        subCfgValue := extractReflectValue(subCfg)
×
UNCOV
299

×
UNCOV
300
                        subCfgValue.FieldByName("NeutrinoCS").Set(
×
UNCOV
301
                                reflect.ValueOf(cc.Cfg.NeutrinoCS),
×
UNCOV
302
                        )
×
303

304
                // RouterRPC isn't conditionally compiled and doesn't need to be
305
                // populated using reflection.
UNCOV
306
                case *routerrpc.Config:
×
UNCOV
307
                        subCfgValue := extractReflectValue(subCfg)
×
UNCOV
308

×
UNCOV
309
                        subCfgValue.FieldByName("AliasMgr").Set(
×
UNCOV
310
                                reflect.ValueOf(aliasMgr),
×
UNCOV
311
                        )
×
312

UNCOV
313
                case *watchtowerrpc.Config:
×
UNCOV
314
                        subCfgValue := extractReflectValue(subCfg)
×
UNCOV
315

×
UNCOV
316
                        subCfgValue.FieldByName("Active").Set(
×
UNCOV
317
                                reflect.ValueOf(tower != nil),
×
UNCOV
318
                        )
×
UNCOV
319
                        subCfgValue.FieldByName("Tower").Set(
×
UNCOV
320
                                reflect.ValueOf(tower),
×
UNCOV
321
                        )
×
322

UNCOV
323
                case *wtclientrpc.Config:
×
UNCOV
324
                        subCfgValue := extractReflectValue(subCfg)
×
UNCOV
325

×
UNCOV
326
                        if towerClientMgr != nil {
×
UNCOV
327
                                subCfgValue.FieldByName("Active").Set(
×
UNCOV
328
                                        reflect.ValueOf(towerClientMgr != nil),
×
UNCOV
329
                                )
×
UNCOV
330
                                subCfgValue.FieldByName("ClientMgr").Set(
×
UNCOV
331
                                        reflect.ValueOf(towerClientMgr),
×
UNCOV
332
                                )
×
UNCOV
333
                        }
×
UNCOV
334
                        subCfgValue.FieldByName("Resolver").Set(
×
UNCOV
335
                                reflect.ValueOf(tcpResolver),
×
UNCOV
336
                        )
×
UNCOV
337
                        subCfgValue.FieldByName("Log").Set(
×
UNCOV
338
                                reflect.ValueOf(rpcLogger),
×
UNCOV
339
                        )
×
340

UNCOV
341
                case *devrpc.Config:
×
UNCOV
342
                        subCfgValue := extractReflectValue(subCfg)
×
UNCOV
343

×
UNCOV
344
                        subCfgValue.FieldByName("ActiveNetParams").Set(
×
UNCOV
345
                                reflect.ValueOf(activeNetParams),
×
UNCOV
346
                        )
×
UNCOV
347

×
UNCOV
348
                        subCfgValue.FieldByName("GraphDB").Set(
×
UNCOV
349
                                reflect.ValueOf(graphDB),
×
UNCOV
350
                        )
×
UNCOV
351

×
UNCOV
352
                        subCfgValue.FieldByName("Switch").Set(
×
UNCOV
353
                                reflect.ValueOf(htlcSwitch),
×
UNCOV
354
                        )
×
355

UNCOV
356
                case *peersrpc.Config:
×
UNCOV
357
                        subCfgValue := extractReflectValue(subCfg)
×
UNCOV
358

×
UNCOV
359
                        subCfgValue.FieldByName("GetNodeAnnouncement").Set(
×
UNCOV
360
                                reflect.ValueOf(getNodeAnnouncement),
×
UNCOV
361
                        )
×
UNCOV
362

×
UNCOV
363
                        subCfgValue.FieldByName("ParseAddr").Set(
×
UNCOV
364
                                reflect.ValueOf(parseAddr),
×
UNCOV
365
                        )
×
UNCOV
366

×
UNCOV
367
                        subCfgValue.FieldByName("UpdateNodeAnnouncement").Set(
×
UNCOV
368
                                reflect.ValueOf(updateNodeAnnouncement),
×
UNCOV
369
                        )
×
370

371
                default:
×
372
                        return fmt.Errorf("unknown field: %v, %T", fieldName,
×
373
                                cfg)
×
374
                }
375
        }
376

377
        // Populate routerrpc dependencies.
UNCOV
378
        s.RouterRPC.NetworkDir = networkDir
×
UNCOV
379
        s.RouterRPC.MacService = macService
×
UNCOV
380
        s.RouterRPC.Router = chanRouter
×
UNCOV
381
        s.RouterRPC.RouterBackend = routerBackend
×
UNCOV
382

×
UNCOV
383
        return nil
×
384
}
385

386
// FetchConfig attempts to locate an existing configuration file mapped to the
387
// target sub-server. If we're unable to find a config file matching the
388
// subServerName name, then false will be returned for the second parameter.
389
//
390
// NOTE: Part of the lnrpc.SubServerConfigDispatcher interface.
UNCOV
391
func (s *subRPCServerConfigs) FetchConfig(subServerName string) (interface{}, bool) {
×
UNCOV
392
        // First, we'll use reflect to obtain a version of the config struct
×
UNCOV
393
        // that allows us to programmatically inspect its fields.
×
UNCOV
394
        selfVal := extractReflectValue(s)
×
UNCOV
395

×
UNCOV
396
        // Now that we have the value of the struct, we can check to see if it
×
UNCOV
397
        // has an attribute with the same name as the subServerName.
×
UNCOV
398
        configVal := selfVal.FieldByName(subServerName)
×
UNCOV
399

×
UNCOV
400
        // We'll now ensure that this field actually exists in this value. If
×
UNCOV
401
        // not, then we'll return false for the ok value to indicate to the
×
UNCOV
402
        // caller that this field doesn't actually exist.
×
UNCOV
403
        if !configVal.IsValid() {
×
404
                return nil, false
×
405
        }
×
406

UNCOV
407
        configValElem := configVal.Elem()
×
UNCOV
408

×
UNCOV
409
        // If a config of this type is found, it doesn't have any fields, then
×
UNCOV
410
        // it's the same as if it wasn't present. This can happen if the build
×
UNCOV
411
        // tag for the sub-server is inactive.
×
UNCOV
412
        if configValElem.NumField() == 0 {
×
413
                return nil, false
×
414
        }
×
415

416
        // At this pint, we know that the field is actually present in the
417
        // config struct, so we can return it directly.
UNCOV
418
        return configVal.Interface(), true
×
419
}
420

421
// extractReflectValue attempts to extract the value from an interface using
422
// the reflect package. The resulting reflect.Value allows the caller to
423
// programmatically examine and manipulate the underlying value.
UNCOV
424
func extractReflectValue(instance interface{}) reflect.Value {
×
UNCOV
425
        var val reflect.Value
×
UNCOV
426

×
UNCOV
427
        // If the type of the instance is a pointer, then we need to deference
×
UNCOV
428
        // the pointer one level to get its value. Otherwise, we can access the
×
UNCOV
429
        // value directly.
×
UNCOV
430
        if reflect.TypeOf(instance).Kind() == reflect.Ptr {
×
UNCOV
431
                val = reflect.ValueOf(instance).Elem()
×
UNCOV
432
        } else {
×
433
                val = reflect.ValueOf(instance)
×
434
        }
×
435

UNCOV
436
        return val
×
437
}
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