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

lightningnetwork / lnd / 13536249039

26 Feb 2025 03:42AM UTC coverage: 57.462% (-1.4%) from 58.835%
13536249039

Pull #8453

github

Roasbeef
peer: update chooseDeliveryScript to gen script if needed

In this commit, we update `chooseDeliveryScript` to generate a new
script if needed. This allows us to fold in a few other lines that
always followed this function into this expanded function.

The tests have been updated accordingly.
Pull Request #8453: [4/4] - multi: integrate new rbf coop close FSM into the existing peer flow

275 of 1318 new or added lines in 22 files covered. (20.86%)

19521 existing lines in 257 files now uncovered.

103858 of 180741 relevant lines covered (57.46%)

24750.23 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("Graph").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