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

lightningnetwork / lnd / 13157733617

05 Feb 2025 12:49PM UTC coverage: 57.712% (-1.1%) from 58.82%
13157733617

Pull #9447

github

yyforyongyu
sweep: rename methods for clarity

We now rename "third party" to "unknown" as the inputs can be spent via
an older sweeping tx, a third party (anchor), or a remote party (pin).
In fee bumper we don't have the info to distinguish the above cases, and
leave them to be further handled by the sweeper as it has more context.
Pull Request #9447: sweep: start tracking input spending status in the fee bumper

83 of 87 new or added lines in 2 files covered. (95.4%)

19472 existing lines in 252 files now uncovered.

103634 of 179570 relevant lines covered (57.71%)

24840.31 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
        "fmt"
5
        "net"
6
        "reflect"
7

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

UNCOV
172
                case *walletrpc.Config:
×
UNCOV
173
                        subCfgValue := extractReflectValue(subCfg)
×
UNCOV
174

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

UNCOV
214
                case *autopilotrpc.Config:
×
UNCOV
215
                        subCfgValue := extractReflectValue(subCfg)
×
UNCOV
216

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

UNCOV
221
                case *chainrpc.Config:
×
UNCOV
222
                        subCfgValue := extractReflectValue(subCfg)
×
UNCOV
223

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

UNCOV
237
                case *invoicesrpc.Config:
×
UNCOV
238
                        subCfgValue := extractReflectValue(subCfg)
×
UNCOV
239

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

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

UNCOV
295
                case *neutrinorpc.Config:
×
UNCOV
296
                        subCfgValue := extractReflectValue(subCfg)
×
UNCOV
297

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

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

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

UNCOV
311
                case *watchtowerrpc.Config:
×
UNCOV
312
                        subCfgValue := extractReflectValue(subCfg)
×
UNCOV
313

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

UNCOV
321
                case *wtclientrpc.Config:
×
UNCOV
322
                        subCfgValue := extractReflectValue(subCfg)
×
UNCOV
323

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

UNCOV
339
                case *devrpc.Config:
×
UNCOV
340
                        subCfgValue := extractReflectValue(subCfg)
×
UNCOV
341

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

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

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

UNCOV
354
                case *peersrpc.Config:
×
UNCOV
355
                        subCfgValue := extractReflectValue(subCfg)
×
UNCOV
356

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

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

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

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

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

×
UNCOV
381
        return nil
×
382
}
383

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

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

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

UNCOV
405
        configValElem := configVal.Elem()
×
UNCOV
406

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

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

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

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

UNCOV
434
        return val
×
435
}
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