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

lightningnetwork / lnd / 14471480810

15 Apr 2025 02:05PM UTC coverage: 58.611% (-10.5%) from 69.088%
14471480810

Pull #9702

github

web-flow
Merge 811aac3b1 into 014706cc3
Pull Request #9702: multi: make payment address mandatory

2 of 4 new or added lines in 1 file covered. (50.0%)

28451 existing lines in 450 files now uncovered.

97194 of 165828 relevant lines covered (58.61%)

1.82 hits per line

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

70.6
/rpcserver.go
1
package lnd
2

3
import (
4
        "bytes"
5
        "context"
6
        "encoding/hex"
7
        "errors"
8
        "fmt"
9
        "io"
10
        "maps"
11
        "math"
12
        "net"
13
        "net/http"
14
        "os"
15
        "path/filepath"
16
        "runtime"
17
        "sort"
18
        "strconv"
19
        "strings"
20
        "sync"
21
        "sync/atomic"
22
        "time"
23

24
        "github.com/btcsuite/btcd/blockchain"
25
        "github.com/btcsuite/btcd/btcec/v2"
26
        "github.com/btcsuite/btcd/btcec/v2/ecdsa"
27
        "github.com/btcsuite/btcd/btcutil"
28
        "github.com/btcsuite/btcd/btcutil/psbt"
29
        "github.com/btcsuite/btcd/chaincfg"
30
        "github.com/btcsuite/btcd/chaincfg/chainhash"
31
        "github.com/btcsuite/btcd/txscript"
32
        "github.com/btcsuite/btcd/wire"
33
        "github.com/btcsuite/btcwallet/waddrmgr"
34
        "github.com/btcsuite/btcwallet/wallet"
35
        "github.com/btcsuite/btcwallet/wallet/txauthor"
36
        "github.com/davecgh/go-spew/spew"
37
        proxy "github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
38
        "github.com/lightningnetwork/lnd/autopilot"
39
        "github.com/lightningnetwork/lnd/build"
40
        "github.com/lightningnetwork/lnd/chainreg"
41
        "github.com/lightningnetwork/lnd/chanacceptor"
42
        "github.com/lightningnetwork/lnd/chanbackup"
43
        "github.com/lightningnetwork/lnd/chanfitness"
44
        "github.com/lightningnetwork/lnd/channeldb"
45
        "github.com/lightningnetwork/lnd/channelnotifier"
46
        "github.com/lightningnetwork/lnd/clock"
47
        "github.com/lightningnetwork/lnd/contractcourt"
48
        "github.com/lightningnetwork/lnd/discovery"
49
        "github.com/lightningnetwork/lnd/feature"
50
        "github.com/lightningnetwork/lnd/fn/v2"
51
        "github.com/lightningnetwork/lnd/funding"
52
        graphdb "github.com/lightningnetwork/lnd/graph/db"
53
        "github.com/lightningnetwork/lnd/graph/db/models"
54
        "github.com/lightningnetwork/lnd/htlcswitch"
55
        "github.com/lightningnetwork/lnd/htlcswitch/hop"
56
        "github.com/lightningnetwork/lnd/input"
57
        "github.com/lightningnetwork/lnd/invoices"
58
        "github.com/lightningnetwork/lnd/keychain"
59
        "github.com/lightningnetwork/lnd/kvdb"
60
        "github.com/lightningnetwork/lnd/labels"
61
        "github.com/lightningnetwork/lnd/lncfg"
62
        "github.com/lightningnetwork/lnd/lnrpc"
63
        "github.com/lightningnetwork/lnd/lnrpc/invoicesrpc"
64
        "github.com/lightningnetwork/lnd/lnrpc/routerrpc"
65
        "github.com/lightningnetwork/lnd/lnrpc/walletrpc"
66
        "github.com/lightningnetwork/lnd/lntypes"
67
        "github.com/lightningnetwork/lnd/lnutils"
68
        "github.com/lightningnetwork/lnd/lnwallet"
69
        "github.com/lightningnetwork/lnd/lnwallet/btcwallet"
70
        "github.com/lightningnetwork/lnd/lnwallet/chainfee"
71
        "github.com/lightningnetwork/lnd/lnwallet/chancloser"
72
        "github.com/lightningnetwork/lnd/lnwallet/chanfunding"
73
        "github.com/lightningnetwork/lnd/lnwire"
74
        "github.com/lightningnetwork/lnd/macaroons"
75
        "github.com/lightningnetwork/lnd/peer"
76
        "github.com/lightningnetwork/lnd/peernotifier"
77
        "github.com/lightningnetwork/lnd/record"
78
        "github.com/lightningnetwork/lnd/routing"
79
        "github.com/lightningnetwork/lnd/routing/blindedpath"
80
        "github.com/lightningnetwork/lnd/routing/route"
81
        "github.com/lightningnetwork/lnd/rpcperms"
82
        "github.com/lightningnetwork/lnd/signal"
83
        "github.com/lightningnetwork/lnd/sweep"
84
        "github.com/lightningnetwork/lnd/tlv"
85
        "github.com/lightningnetwork/lnd/watchtower"
86
        "github.com/lightningnetwork/lnd/zpay32"
87
        "github.com/tv42/zbase32"
88
        "google.golang.org/grpc"
89
        "google.golang.org/grpc/codes"
90
        "google.golang.org/grpc/status"
91
        "google.golang.org/protobuf/proto"
92
        "gopkg.in/macaroon-bakery.v2/bakery"
93
)
94

95
const (
96
        // defaultNumBlocksEstimate is the number of blocks that we fall back
97
        // to issuing an estimate for if a fee pre fence doesn't specify an
98
        // explicit conf target or fee rate.
99
        defaultNumBlocksEstimate = 6
100
)
101

102
var (
103
        // readPermissions is a slice of all entities that allow read
104
        // permissions for authorization purposes, all lowercase.
105
        readPermissions = []bakery.Op{
106
                {
107
                        Entity: "onchain",
108
                        Action: "read",
109
                },
110
                {
111
                        Entity: "offchain",
112
                        Action: "read",
113
                },
114
                {
115
                        Entity: "address",
116
                        Action: "read",
117
                },
118
                {
119
                        Entity: "message",
120
                        Action: "read",
121
                },
122
                {
123
                        Entity: "peers",
124
                        Action: "read",
125
                },
126
                {
127
                        Entity: "info",
128
                        Action: "read",
129
                },
130
                {
131
                        Entity: "invoices",
132
                        Action: "read",
133
                },
134
                {
135
                        Entity: "signer",
136
                        Action: "read",
137
                },
138
                {
139
                        Entity: "macaroon",
140
                        Action: "read",
141
                },
142
        }
143

144
        // writePermissions is a slice of all entities that allow write
145
        // permissions for authorization purposes, all lowercase.
146
        writePermissions = []bakery.Op{
147
                {
148
                        Entity: "onchain",
149
                        Action: "write",
150
                },
151
                {
152
                        Entity: "offchain",
153
                        Action: "write",
154
                },
155
                {
156
                        Entity: "address",
157
                        Action: "write",
158
                },
159
                {
160
                        Entity: "message",
161
                        Action: "write",
162
                },
163
                {
164
                        Entity: "peers",
165
                        Action: "write",
166
                },
167
                {
168
                        Entity: "info",
169
                        Action: "write",
170
                },
171
                {
172
                        Entity: "invoices",
173
                        Action: "write",
174
                },
175
                {
176
                        Entity: "signer",
177
                        Action: "generate",
178
                },
179
                {
180
                        Entity: "macaroon",
181
                        Action: "generate",
182
                },
183
                {
184
                        Entity: "macaroon",
185
                        Action: "write",
186
                },
187
        }
188

189
        // invoicePermissions is a slice of all the entities that allows a user
190
        // to only access calls that are related to invoices, so: streaming
191
        // RPCs, generating, and listening invoices.
192
        invoicePermissions = []bakery.Op{
193
                {
194
                        Entity: "invoices",
195
                        Action: "read",
196
                },
197
                {
198
                        Entity: "invoices",
199
                        Action: "write",
200
                },
201
                {
202
                        Entity: "address",
203
                        Action: "read",
204
                },
205
                {
206
                        Entity: "address",
207
                        Action: "write",
208
                },
209
                {
210
                        Entity: "onchain",
211
                        Action: "read",
212
                },
213
        }
214

215
        // TODO(guggero): Refactor into constants that are used for all
216
        // permissions in this file. Also expose the list of possible
217
        // permissions in an RPC when per RPC permissions are
218
        // implemented.
219
        validActions  = []string{"read", "write", "generate"}
220
        validEntities = []string{
221
                "onchain", "offchain", "address", "message",
222
                "peers", "info", "invoices", "signer", "macaroon",
223
                macaroons.PermissionEntityCustomURI,
224
        }
225

226
        // If the --no-macaroons flag is used to start lnd, the macaroon service
227
        // is not initialized. errMacaroonDisabled is then returned when
228
        // macaroon related services are used.
229
        errMacaroonDisabled = fmt.Errorf("macaroon authentication disabled, " +
230
                "remove --no-macaroons flag to enable")
231
)
232

233
// stringInSlice returns true if a string is contained in the given slice.
234
func stringInSlice(a string, slice []string) bool {
3✔
235
        for _, b := range slice {
6✔
236
                if b == a {
6✔
237
                        return true
3✔
238
                }
3✔
239
        }
240
        return false
3✔
241
}
242

243
// GetAllPermissions returns all the permissions required to interact with lnd.
UNCOV
244
func GetAllPermissions() []bakery.Op {
×
UNCOV
245
        allPerms := make([]bakery.Op, 0)
×
UNCOV
246

×
UNCOV
247
        // The map will help keep track of which specific permission pairs have
×
UNCOV
248
        // already been added to the slice.
×
UNCOV
249
        allPermsMap := make(map[string]map[string]struct{})
×
UNCOV
250

×
UNCOV
251
        for _, perms := range MainRPCServerPermissions() {
×
UNCOV
252
                for _, perm := range perms {
×
UNCOV
253
                        entity := perm.Entity
×
UNCOV
254
                        action := perm.Action
×
UNCOV
255

×
UNCOV
256
                        // If this specific entity-action permission pair isn't
×
UNCOV
257
                        // in the map yet. Add it to map, and the permission
×
UNCOV
258
                        // slice.
×
UNCOV
259
                        if acts, ok := allPermsMap[entity]; ok {
×
UNCOV
260
                                if _, ok := acts[action]; !ok {
×
UNCOV
261
                                        allPermsMap[entity][action] = struct{}{}
×
UNCOV
262

×
UNCOV
263
                                        allPerms = append(
×
UNCOV
264
                                                allPerms, perm,
×
UNCOV
265
                                        )
×
UNCOV
266
                                }
×
UNCOV
267
                        } else {
×
UNCOV
268
                                allPermsMap[entity] = make(map[string]struct{})
×
UNCOV
269
                                allPermsMap[entity][action] = struct{}{}
×
UNCOV
270
                                allPerms = append(allPerms, perm)
×
UNCOV
271
                        }
×
272
                }
273
        }
274

UNCOV
275
        return allPerms
×
276
}
277

278
// MainRPCServerPermissions returns a mapping of the main RPC server calls to
279
// the permissions they require.
280
func MainRPCServerPermissions() map[string][]bakery.Op {
3✔
281
        return map[string][]bakery.Op{
3✔
282
                "/lnrpc.Lightning/SendCoins": {{
3✔
283
                        Entity: "onchain",
3✔
284
                        Action: "write",
3✔
285
                }},
3✔
286
                "/lnrpc.Lightning/ListUnspent": {{
3✔
287
                        Entity: "onchain",
3✔
288
                        Action: "read",
3✔
289
                }},
3✔
290
                "/lnrpc.Lightning/SendMany": {{
3✔
291
                        Entity: "onchain",
3✔
292
                        Action: "write",
3✔
293
                }},
3✔
294
                "/lnrpc.Lightning/NewAddress": {{
3✔
295
                        Entity: "address",
3✔
296
                        Action: "write",
3✔
297
                }},
3✔
298
                "/lnrpc.Lightning/SignMessage": {{
3✔
299
                        Entity: "message",
3✔
300
                        Action: "write",
3✔
301
                }},
3✔
302
                "/lnrpc.Lightning/VerifyMessage": {{
3✔
303
                        Entity: "message",
3✔
304
                        Action: "read",
3✔
305
                }},
3✔
306
                "/lnrpc.Lightning/ConnectPeer": {{
3✔
307
                        Entity: "peers",
3✔
308
                        Action: "write",
3✔
309
                }},
3✔
310
                "/lnrpc.Lightning/DisconnectPeer": {{
3✔
311
                        Entity: "peers",
3✔
312
                        Action: "write",
3✔
313
                }},
3✔
314
                "/lnrpc.Lightning/OpenChannel": {{
3✔
315
                        Entity: "onchain",
3✔
316
                        Action: "write",
3✔
317
                }, {
3✔
318
                        Entity: "offchain",
3✔
319
                        Action: "write",
3✔
320
                }},
3✔
321
                "/lnrpc.Lightning/BatchOpenChannel": {{
3✔
322
                        Entity: "onchain",
3✔
323
                        Action: "write",
3✔
324
                }, {
3✔
325
                        Entity: "offchain",
3✔
326
                        Action: "write",
3✔
327
                }},
3✔
328
                "/lnrpc.Lightning/OpenChannelSync": {{
3✔
329
                        Entity: "onchain",
3✔
330
                        Action: "write",
3✔
331
                }, {
3✔
332
                        Entity: "offchain",
3✔
333
                        Action: "write",
3✔
334
                }},
3✔
335
                "/lnrpc.Lightning/CloseChannel": {{
3✔
336
                        Entity: "onchain",
3✔
337
                        Action: "write",
3✔
338
                }, {
3✔
339
                        Entity: "offchain",
3✔
340
                        Action: "write",
3✔
341
                }},
3✔
342
                "/lnrpc.Lightning/AbandonChannel": {{
3✔
343
                        Entity: "offchain",
3✔
344
                        Action: "write",
3✔
345
                }},
3✔
346
                "/lnrpc.Lightning/GetInfo": {{
3✔
347
                        Entity: "info",
3✔
348
                        Action: "read",
3✔
349
                }},
3✔
350
                "/lnrpc.Lightning/GetDebugInfo": {{
3✔
351
                        Entity: "info",
3✔
352
                        Action: "read",
3✔
353
                }, {
3✔
354
                        Entity: "offchain",
3✔
355
                        Action: "read",
3✔
356
                }, {
3✔
357
                        Entity: "onchain",
3✔
358
                        Action: "read",
3✔
359
                }, {
3✔
360
                        Entity: "peers",
3✔
361
                        Action: "read",
3✔
362
                }},
3✔
363
                "/lnrpc.Lightning/GetRecoveryInfo": {{
3✔
364
                        Entity: "info",
3✔
365
                        Action: "read",
3✔
366
                }},
3✔
367
                "/lnrpc.Lightning/ListPeers": {{
3✔
368
                        Entity: "peers",
3✔
369
                        Action: "read",
3✔
370
                }},
3✔
371
                "/lnrpc.Lightning/WalletBalance": {{
3✔
372
                        Entity: "onchain",
3✔
373
                        Action: "read",
3✔
374
                }},
3✔
375
                "/lnrpc.Lightning/EstimateFee": {{
3✔
376
                        Entity: "onchain",
3✔
377
                        Action: "read",
3✔
378
                }},
3✔
379
                "/lnrpc.Lightning/ChannelBalance": {{
3✔
380
                        Entity: "offchain",
3✔
381
                        Action: "read",
3✔
382
                }},
3✔
383
                "/lnrpc.Lightning/PendingChannels": {{
3✔
384
                        Entity: "offchain",
3✔
385
                        Action: "read",
3✔
386
                }},
3✔
387
                "/lnrpc.Lightning/ListChannels": {{
3✔
388
                        Entity: "offchain",
3✔
389
                        Action: "read",
3✔
390
                }},
3✔
391
                "/lnrpc.Lightning/SubscribeChannelEvents": {{
3✔
392
                        Entity: "offchain",
3✔
393
                        Action: "read",
3✔
394
                }},
3✔
395
                "/lnrpc.Lightning/ClosedChannels": {{
3✔
396
                        Entity: "offchain",
3✔
397
                        Action: "read",
3✔
398
                }},
3✔
399
                "/lnrpc.Lightning/SendPayment": {{
3✔
400
                        Entity: "offchain",
3✔
401
                        Action: "write",
3✔
402
                }},
3✔
403
                "/lnrpc.Lightning/SendPaymentSync": {{
3✔
404
                        Entity: "offchain",
3✔
405
                        Action: "write",
3✔
406
                }},
3✔
407
                "/lnrpc.Lightning/SendToRoute": {{
3✔
408
                        Entity: "offchain",
3✔
409
                        Action: "write",
3✔
410
                }},
3✔
411
                "/lnrpc.Lightning/SendToRouteSync": {{
3✔
412
                        Entity: "offchain",
3✔
413
                        Action: "write",
3✔
414
                }},
3✔
415
                "/lnrpc.Lightning/AddInvoice": {{
3✔
416
                        Entity: "invoices",
3✔
417
                        Action: "write",
3✔
418
                }},
3✔
419
                "/lnrpc.Lightning/LookupInvoice": {{
3✔
420
                        Entity: "invoices",
3✔
421
                        Action: "read",
3✔
422
                }},
3✔
423
                "/lnrpc.Lightning/ListInvoices": {{
3✔
424
                        Entity: "invoices",
3✔
425
                        Action: "read",
3✔
426
                }},
3✔
427
                "/lnrpc.Lightning/SubscribeInvoices": {{
3✔
428
                        Entity: "invoices",
3✔
429
                        Action: "read",
3✔
430
                }},
3✔
431
                "/lnrpc.Lightning/SubscribeTransactions": {{
3✔
432
                        Entity: "onchain",
3✔
433
                        Action: "read",
3✔
434
                }},
3✔
435
                "/lnrpc.Lightning/GetTransactions": {{
3✔
436
                        Entity: "onchain",
3✔
437
                        Action: "read",
3✔
438
                }},
3✔
439
                "/lnrpc.Lightning/DescribeGraph": {{
3✔
440
                        Entity: "info",
3✔
441
                        Action: "read",
3✔
442
                }},
3✔
443
                "/lnrpc.Lightning/GetNodeMetrics": {{
3✔
444
                        Entity: "info",
3✔
445
                        Action: "read",
3✔
446
                }},
3✔
447
                "/lnrpc.Lightning/GetChanInfo": {{
3✔
448
                        Entity: "info",
3✔
449
                        Action: "read",
3✔
450
                }},
3✔
451
                "/lnrpc.Lightning/GetNodeInfo": {{
3✔
452
                        Entity: "info",
3✔
453
                        Action: "read",
3✔
454
                }},
3✔
455
                "/lnrpc.Lightning/QueryRoutes": {{
3✔
456
                        Entity: "info",
3✔
457
                        Action: "read",
3✔
458
                }},
3✔
459
                "/lnrpc.Lightning/GetNetworkInfo": {{
3✔
460
                        Entity: "info",
3✔
461
                        Action: "read",
3✔
462
                }},
3✔
463
                "/lnrpc.Lightning/StopDaemon": {{
3✔
464
                        Entity: "info",
3✔
465
                        Action: "write",
3✔
466
                }},
3✔
467
                "/lnrpc.Lightning/SubscribeChannelGraph": {{
3✔
468
                        Entity: "info",
3✔
469
                        Action: "read",
3✔
470
                }},
3✔
471
                "/lnrpc.Lightning/ListPayments": {{
3✔
472
                        Entity: "offchain",
3✔
473
                        Action: "read",
3✔
474
                }},
3✔
475
                "/lnrpc.Lightning/DeletePayment": {{
3✔
476
                        Entity: "offchain",
3✔
477
                        Action: "write",
3✔
478
                }},
3✔
479
                "/lnrpc.Lightning/DeleteAllPayments": {{
3✔
480
                        Entity: "offchain",
3✔
481
                        Action: "write",
3✔
482
                }},
3✔
483
                "/lnrpc.Lightning/DebugLevel": {{
3✔
484
                        Entity: "info",
3✔
485
                        Action: "write",
3✔
486
                }},
3✔
487
                "/lnrpc.Lightning/DecodePayReq": {{
3✔
488
                        Entity: "offchain",
3✔
489
                        Action: "read",
3✔
490
                }},
3✔
491
                "/lnrpc.Lightning/FeeReport": {{
3✔
492
                        Entity: "offchain",
3✔
493
                        Action: "read",
3✔
494
                }},
3✔
495
                "/lnrpc.Lightning/UpdateChannelPolicy": {{
3✔
496
                        Entity: "offchain",
3✔
497
                        Action: "write",
3✔
498
                }},
3✔
499
                "/lnrpc.Lightning/ForwardingHistory": {{
3✔
500
                        Entity: "offchain",
3✔
501
                        Action: "read",
3✔
502
                }},
3✔
503
                "/lnrpc.Lightning/RestoreChannelBackups": {{
3✔
504
                        Entity: "offchain",
3✔
505
                        Action: "write",
3✔
506
                }},
3✔
507
                "/lnrpc.Lightning/ExportChannelBackup": {{
3✔
508
                        Entity: "offchain",
3✔
509
                        Action: "read",
3✔
510
                }},
3✔
511
                "/lnrpc.Lightning/VerifyChanBackup": {{
3✔
512
                        Entity: "offchain",
3✔
513
                        Action: "read",
3✔
514
                }},
3✔
515
                "/lnrpc.Lightning/ExportAllChannelBackups": {{
3✔
516
                        Entity: "offchain",
3✔
517
                        Action: "read",
3✔
518
                }},
3✔
519
                "/lnrpc.Lightning/SubscribeChannelBackups": {{
3✔
520
                        Entity: "offchain",
3✔
521
                        Action: "read",
3✔
522
                }},
3✔
523
                "/lnrpc.Lightning/ChannelAcceptor": {{
3✔
524
                        Entity: "onchain",
3✔
525
                        Action: "write",
3✔
526
                }, {
3✔
527
                        Entity: "offchain",
3✔
528
                        Action: "write",
3✔
529
                }},
3✔
530
                "/lnrpc.Lightning/BakeMacaroon": {{
3✔
531
                        Entity: "macaroon",
3✔
532
                        Action: "generate",
3✔
533
                }},
3✔
534
                "/lnrpc.Lightning/ListMacaroonIDs": {{
3✔
535
                        Entity: "macaroon",
3✔
536
                        Action: "read",
3✔
537
                }},
3✔
538
                "/lnrpc.Lightning/DeleteMacaroonID": {{
3✔
539
                        Entity: "macaroon",
3✔
540
                        Action: "write",
3✔
541
                }},
3✔
542
                "/lnrpc.Lightning/ListPermissions": {{
3✔
543
                        Entity: "info",
3✔
544
                        Action: "read",
3✔
545
                }},
3✔
546
                "/lnrpc.Lightning/CheckMacaroonPermissions": {{
3✔
547
                        Entity: "macaroon",
3✔
548
                        Action: "read",
3✔
549
                }},
3✔
550
                "/lnrpc.Lightning/SubscribePeerEvents": {{
3✔
551
                        Entity: "peers",
3✔
552
                        Action: "read",
3✔
553
                }},
3✔
554
                "/lnrpc.Lightning/FundingStateStep": {{
3✔
555
                        Entity: "onchain",
3✔
556
                        Action: "write",
3✔
557
                }, {
3✔
558
                        Entity: "offchain",
3✔
559
                        Action: "write",
3✔
560
                }},
3✔
561
                lnrpc.RegisterRPCMiddlewareURI: {{
3✔
562
                        Entity: "macaroon",
3✔
563
                        Action: "write",
3✔
564
                }},
3✔
565
                "/lnrpc.Lightning/SendCustomMessage": {{
3✔
566
                        Entity: "offchain",
3✔
567
                        Action: "write",
3✔
568
                }},
3✔
569
                "/lnrpc.Lightning/SubscribeCustomMessages": {{
3✔
570
                        Entity: "offchain",
3✔
571
                        Action: "read",
3✔
572
                }},
3✔
573
                "/lnrpc.Lightning/LookupHtlcResolution": {{
3✔
574
                        Entity: "offchain",
3✔
575
                        Action: "read",
3✔
576
                }},
3✔
577
                "/lnrpc.Lightning/ListAliases": {{
3✔
578
                        Entity: "offchain",
3✔
579
                        Action: "read",
3✔
580
                }},
3✔
581
        }
3✔
582
}
3✔
583

584
// AuxDataParser is an interface that is used to parse auxiliary custom data
585
// within RPC messages. This is used to transform binary blobs to human-readable
586
// JSON representations.
587
type AuxDataParser interface {
588
        // InlineParseCustomData replaces any custom data binary blob in the
589
        // given RPC message with its corresponding JSON formatted data. This
590
        // transforms the binary (likely TLV encoded) data to a human-readable
591
        // JSON representation (still as byte slice).
592
        InlineParseCustomData(msg proto.Message) error
593
}
594

595
// rpcServer is a gRPC, RPC front end to the lnd daemon.
596
// TODO(roasbeef): pagination support for the list-style calls
597
type rpcServer struct {
598
        started  int32 // To be used atomically.
599
        shutdown int32 // To be used atomically.
600

601
        // Required by the grpc-gateway/v2 library for forward compatibility.
602
        // Must be after the atomically used variables to not break struct
603
        // alignment.
604
        lnrpc.UnimplementedLightningServer
605

606
        server *server
607

608
        cfg *Config
609

610
        // subServers are a set of sub-RPC servers that use the same gRPC and
611
        // listening sockets as the main RPC server, but which maintain their
612
        // own independent service. This allows us to expose a set of
613
        // micro-service like abstractions to the outside world for users to
614
        // consume.
615
        subServers      []lnrpc.SubServer
616
        subGrpcHandlers []lnrpc.GrpcHandler
617

618
        // routerBackend contains the backend implementation of the router
619
        // rpc sub server.
620
        routerBackend *routerrpc.RouterBackend
621

622
        // chanPredicate is used in the bidirectional ChannelAcceptor streaming
623
        // method.
624
        chanPredicate chanacceptor.MultiplexAcceptor
625

626
        quit chan struct{}
627

628
        // macService is the macaroon service that we need to mint new
629
        // macaroons.
630
        macService *macaroons.Service
631

632
        // selfNode is our own pubkey.
633
        selfNode route.Vertex
634

635
        // interceptorChain is the interceptor added to our gRPC server.
636
        interceptorChain *rpcperms.InterceptorChain
637

638
        // implCfg is the configuration for some of the interfaces that can be
639
        // provided externally.
640
        implCfg *ImplementationCfg
641

642
        // interceptor is used to be able to request a shutdown
643
        interceptor signal.Interceptor
644

645
        graphCache        sync.RWMutex
646
        describeGraphResp *lnrpc.ChannelGraph
647
        graphCacheEvictor *time.Timer
648
}
649

650
// A compile time check to ensure that rpcServer fully implements the
651
// LightningServer gRPC service.
652
var _ lnrpc.LightningServer = (*rpcServer)(nil)
653

654
// newRPCServer creates and returns a new instance of the rpcServer. Before
655
// dependencies are added, this will be an non-functioning RPC server only to
656
// be used to register the LightningService with the gRPC server.
657
func newRPCServer(cfg *Config, interceptorChain *rpcperms.InterceptorChain,
658
        implCfg *ImplementationCfg, interceptor signal.Interceptor) *rpcServer {
3✔
659

3✔
660
        // We go trhough the list of registered sub-servers, and create a gRPC
3✔
661
        // handler for each. These are used to register with the gRPC server
3✔
662
        // before all dependencies are available.
3✔
663
        registeredSubServers := lnrpc.RegisteredSubServers()
3✔
664

3✔
665
        var subServerHandlers []lnrpc.GrpcHandler
3✔
666
        for _, subServer := range registeredSubServers {
6✔
667
                subServerHandlers = append(
3✔
668
                        subServerHandlers, subServer.NewGrpcHandler(),
3✔
669
                )
3✔
670
        }
3✔
671

672
        return &rpcServer{
3✔
673
                cfg:              cfg,
3✔
674
                subGrpcHandlers:  subServerHandlers,
3✔
675
                interceptorChain: interceptorChain,
3✔
676
                implCfg:          implCfg,
3✔
677
                quit:             make(chan struct{}, 1),
3✔
678
                interceptor:      interceptor,
3✔
679
        }
3✔
680
}
681

682
// addDeps populates all dependencies needed by the RPC server, and any
683
// of the sub-servers that it maintains. When this is done, the RPC server can
684
// be started, and start accepting RPC calls.
685
func (r *rpcServer) addDeps(s *server, macService *macaroons.Service,
686
        subServerCgs *subRPCServerConfigs, atpl *autopilot.Manager,
687
        invoiceRegistry *invoices.InvoiceRegistry, tower *watchtower.Standalone,
688
        chanPredicate chanacceptor.MultiplexAcceptor,
689
        invoiceHtlcModifier *invoices.HtlcModificationInterceptor) error {
3✔
690

3✔
691
        // Set up router rpc backend.
3✔
692
        selfNode, err := s.graphDB.SourceNode()
3✔
693
        if err != nil {
3✔
694
                return err
×
695
        }
×
696
        graph := s.graphDB
3✔
697

3✔
698
        routerBackend := &routerrpc.RouterBackend{
3✔
699
                SelfNode: selfNode.PubKeyBytes,
3✔
700
                FetchChannelCapacity: func(chanID uint64) (btcutil.Amount,
3✔
701
                        error) {
6✔
702

3✔
703
                        info, _, _, err := graph.FetchChannelEdgesByID(chanID)
3✔
704
                        if err != nil {
6✔
705
                                return 0, err
3✔
706
                        }
3✔
707
                        return info.Capacity, nil
3✔
708
                },
709
                FetchAmountPairCapacity: func(nodeFrom, nodeTo route.Vertex,
710
                        amount lnwire.MilliSatoshi) (btcutil.Amount, error) {
3✔
711

3✔
712
                        return routing.FetchAmountPairCapacity(
3✔
713
                                graph, selfNode.PubKeyBytes, nodeFrom, nodeTo,
3✔
714
                                amount,
3✔
715
                        )
3✔
716
                },
3✔
717
                FetchChannelEndpoints: func(chanID uint64) (route.Vertex,
718
                        route.Vertex, error) {
3✔
719

3✔
720
                        info, _, _, err := graph.FetchChannelEdgesByID(
3✔
721
                                chanID,
3✔
722
                        )
3✔
723
                        if err != nil {
6✔
724
                                return route.Vertex{}, route.Vertex{},
3✔
725
                                        fmt.Errorf("unable to fetch channel "+
3✔
726
                                                "edges by channel ID %d: %v",
3✔
727
                                                chanID, err)
3✔
728
                        }
3✔
729

730
                        return info.NodeKey1Bytes, info.NodeKey2Bytes, nil
×
731
                },
732
                FindRoute:              s.chanRouter.FindRoute,
733
                MissionControl:         s.defaultMC,
734
                ActiveNetParams:        r.cfg.ActiveNetParams.Params,
735
                Tower:                  s.controlTower,
736
                MaxTotalTimelock:       r.cfg.MaxOutgoingCltvExpiry,
737
                DefaultFinalCltvDelta:  uint16(r.cfg.Bitcoin.TimeLockDelta),
738
                SubscribeHtlcEvents:    s.htlcNotifier.SubscribeHtlcEvents,
739
                InterceptableForwarder: s.interceptableSwitch,
740
                SetChannelEnabled: func(outpoint wire.OutPoint) error {
3✔
741
                        return s.chanStatusMgr.RequestEnable(outpoint, true)
3✔
742
                },
3✔
743
                SetChannelDisabled: func(outpoint wire.OutPoint) error {
3✔
744
                        return s.chanStatusMgr.RequestDisable(outpoint, true)
3✔
745
                },
3✔
746
                SetChannelAuto:     s.chanStatusMgr.RequestAuto,
747
                UseStatusInitiated: subServerCgs.RouterRPC.UseStatusInitiated,
748
                ParseCustomChannelData: func(msg proto.Message) error {
3✔
749
                        err = fn.MapOptionZ(
3✔
750
                                r.server.implCfg.AuxDataParser,
3✔
751
                                func(parser AuxDataParser) error {
3✔
752
                                        return parser.InlineParseCustomData(msg)
×
753
                                },
×
754
                        )
755
                        if err != nil {
3✔
756
                                return fmt.Errorf("error parsing custom data: "+
×
757
                                        "%w", err)
×
758
                        }
×
759

760
                        return nil
3✔
761
                },
762
                ShouldSetExpEndorsement: func() bool {
3✔
763
                        if s.cfg.ProtocolOptions.NoExperimentalEndorsement() {
3✔
764
                                return false
×
765
                        }
×
766

767
                        return clock.NewDefaultClock().Now().Before(
3✔
768
                                EndorsementExperimentEnd,
3✔
769
                        )
3✔
770
                },
771
        }
772

773
        genInvoiceFeatures := func() *lnwire.FeatureVector {
6✔
774
                return s.featureMgr.Get(feature.SetInvoice)
3✔
775
        }
3✔
776
        genAmpInvoiceFeatures := func() *lnwire.FeatureVector {
3✔
777
                return s.featureMgr.Get(feature.SetInvoiceAmp)
×
778
        }
×
779

780
        parseAddr := func(addr string) (net.Addr, error) {
6✔
781
                return parseAddr(addr, r.cfg.net)
3✔
782
        }
3✔
783

784
        var (
3✔
785
                subServers     []lnrpc.SubServer
3✔
786
                subServerPerms []lnrpc.MacaroonPerms
3✔
787
        )
3✔
788

3✔
789
        // Before we create any of the sub-servers, we need to ensure that all
3✔
790
        // the dependencies they need are properly populated within each sub
3✔
791
        // server configuration struct.
3✔
792
        //
3✔
793
        // TODO(roasbeef): extend sub-sever config to have both (local vs remote) DB
3✔
794
        err = subServerCgs.PopulateDependencies(
3✔
795
                r.cfg, s.cc, r.cfg.networkDir, macService, atpl, invoiceRegistry,
3✔
796
                s.htlcSwitch, r.cfg.ActiveNetParams.Params, s.chanRouter,
3✔
797
                routerBackend, s.nodeSigner, s.graphDB, s.chanStateDB,
3✔
798
                s.sweeper, tower, s.towerClientMgr, r.cfg.net.ResolveTCPAddr,
3✔
799
                genInvoiceFeatures, genAmpInvoiceFeatures,
3✔
800
                s.getNodeAnnouncement, s.updateAndBroadcastSelfNode, parseAddr,
3✔
801
                rpcsLog, s.aliasMgr, r.implCfg.AuxDataParser,
3✔
802
                invoiceHtlcModifier,
3✔
803
        )
3✔
804
        if err != nil {
3✔
805
                return err
×
806
        }
×
807

808
        // Now that the sub-servers have all their dependencies in place, we
809
        // can create each sub-server!
810
        for _, subServerInstance := range r.subGrpcHandlers {
6✔
811
                subServer, macPerms, err := subServerInstance.CreateSubServer(
3✔
812
                        subServerCgs,
3✔
813
                )
3✔
814
                if err != nil {
3✔
815
                        return err
×
816
                }
×
817

818
                // We'll collect the sub-server, and also the set of
819
                // permissions it needs for macaroons so we can apply the
820
                // interceptors below.
821
                subServers = append(subServers, subServer)
3✔
822
                subServerPerms = append(subServerPerms, macPerms)
3✔
823
        }
824

825
        // Next, we need to merge the set of sub server macaroon permissions
826
        // with the main RPC server permissions so we can unite them under a
827
        // single set of interceptors.
828
        for m, ops := range MainRPCServerPermissions() {
6✔
829
                err := r.interceptorChain.AddPermission(m, ops)
3✔
830
                if err != nil {
3✔
831
                        return err
×
832
                }
×
833
        }
834

835
        for _, subServerPerm := range subServerPerms {
6✔
836
                for method, ops := range subServerPerm {
6✔
837
                        err := r.interceptorChain.AddPermission(method, ops)
3✔
838
                        if err != nil {
3✔
839
                                return err
×
840
                        }
×
841
                }
842
        }
843

844
        // External subserver possibly need to register their own permissions
845
        // and macaroon validator.
846
        for method, ops := range r.implCfg.ExternalValidator.Permissions() {
3✔
847
                err := r.interceptorChain.AddPermission(method, ops)
×
848
                if err != nil {
×
849
                        return err
×
850
                }
×
851

852
                // Give the external subservers the possibility to also use
853
                // their own validator to check any macaroons attached to calls
854
                // to this method. This allows them to have their own root key
855
                // ID database and permission entities.
856
                err = macService.RegisterExternalValidator(
×
857
                        method, r.implCfg.ExternalValidator,
×
858
                )
×
859
                if err != nil {
×
860
                        return fmt.Errorf("could not register external "+
×
861
                                "macaroon validator: %v", err)
×
862
                }
×
863
        }
864

865
        // Finally, with all the set up complete, add the last dependencies to
866
        // the rpc server.
867
        r.server = s
3✔
868
        r.subServers = subServers
3✔
869
        r.routerBackend = routerBackend
3✔
870
        r.chanPredicate = chanPredicate
3✔
871
        r.macService = macService
3✔
872
        r.selfNode = selfNode.PubKeyBytes
3✔
873

3✔
874
        graphCacheDuration := r.cfg.Caches.RPCGraphCacheDuration
3✔
875
        if graphCacheDuration != 0 {
6✔
876
                r.graphCacheEvictor = time.AfterFunc(graphCacheDuration, func() {
6✔
877
                        // Grab the mutex and purge the current populated
3✔
878
                        // describe graph response.
3✔
879
                        r.graphCache.Lock()
3✔
880
                        defer r.graphCache.Unlock()
3✔
881

3✔
882
                        r.describeGraphResp = nil
3✔
883

3✔
884
                        // Reset ourselves as well at the end so we run again
3✔
885
                        // after the duration.
3✔
886
                        r.graphCacheEvictor.Reset(graphCacheDuration)
3✔
887
                })
3✔
888
        }
889

890
        return nil
3✔
891
}
892

893
// RegisterWithGrpcServer registers the rpcServer and any subservers with the
894
// root gRPC server.
895
func (r *rpcServer) RegisterWithGrpcServer(grpcServer *grpc.Server) error {
3✔
896
        // Register the main RPC server.
3✔
897
        lnrpc.RegisterLightningServer(grpcServer, r)
3✔
898

3✔
899
        // Now the main RPC server has been registered, we'll iterate through
3✔
900
        // all the sub-RPC servers and register them to ensure that requests
3✔
901
        // are properly routed towards them.
3✔
902
        for _, subServer := range r.subGrpcHandlers {
6✔
903
                err := subServer.RegisterWithRootServer(grpcServer)
3✔
904
                if err != nil {
3✔
905
                        return fmt.Errorf("unable to register "+
×
906
                                "sub-server with root: %v", err)
×
907
                }
×
908
        }
909

910
        // Before actually listening on the gRPC listener, give external
911
        // subservers the chance to register to our gRPC server. Those external
912
        // subservers (think GrUB) are responsible for starting/stopping on
913
        // their own, we just let them register their services to the same
914
        // server instance so all of them can be exposed on the same
915
        // port/listener.
916
        err := r.implCfg.RegisterGrpcSubserver(grpcServer)
3✔
917
        if err != nil {
3✔
918
                rpcsLog.Errorf("error registering external gRPC "+
×
919
                        "subserver: %v", err)
×
920
        }
×
921

922
        return nil
3✔
923
}
924

925
// Start launches any helper goroutines required for the rpcServer to function.
926
func (r *rpcServer) Start() error {
3✔
927
        if atomic.AddInt32(&r.started, 1) != 1 {
3✔
928
                return nil
×
929
        }
×
930

931
        // First, we'll start all the sub-servers to ensure that they're ready
932
        // to take new requests in.
933
        //
934
        // TODO(roasbeef): some may require that the entire daemon be started
935
        // at that point
936
        for _, subServer := range r.subServers {
6✔
937
                rpcsLog.Debugf("Starting sub RPC server: %v", subServer.Name())
3✔
938

3✔
939
                if err := subServer.Start(); err != nil {
3✔
940
                        return err
×
941
                }
×
942
        }
943

944
        return nil
3✔
945
}
946

947
// RegisterWithRestProxy registers the RPC server and any subservers with the
948
// given REST proxy.
949
func (r *rpcServer) RegisterWithRestProxy(restCtx context.Context,
950
        restMux *proxy.ServeMux, restDialOpts []grpc.DialOption,
951
        restProxyDest string) error {
3✔
952

3✔
953
        // With our custom REST proxy mux created, register our main RPC and
3✔
954
        // give all subservers a chance to register as well.
3✔
955
        err := lnrpc.RegisterLightningHandlerFromEndpoint(
3✔
956
                restCtx, restMux, restProxyDest, restDialOpts,
3✔
957
        )
3✔
958
        if err != nil {
3✔
959
                return err
×
960
        }
×
961

962
        // Register our State service with the REST proxy.
963
        err = lnrpc.RegisterStateHandlerFromEndpoint(
3✔
964
                restCtx, restMux, restProxyDest, restDialOpts,
3✔
965
        )
3✔
966
        if err != nil {
3✔
967
                return err
×
968
        }
×
969

970
        // Register all the subservers with the REST proxy.
971
        for _, subServer := range r.subGrpcHandlers {
6✔
972
                err := subServer.RegisterWithRestServer(
3✔
973
                        restCtx, restMux, restProxyDest, restDialOpts,
3✔
974
                )
3✔
975
                if err != nil {
3✔
976
                        return fmt.Errorf("unable to register REST sub-server "+
×
977
                                "with root: %v", err)
×
978
                }
×
979
        }
980

981
        // Before listening on any of the interfaces, we also want to give the
982
        // external subservers a chance to register their own REST proxy stub
983
        // with our mux instance.
984
        err = r.implCfg.RegisterRestSubserver(
3✔
985
                restCtx, restMux, restProxyDest, restDialOpts,
3✔
986
        )
3✔
987
        if err != nil {
3✔
988
                rpcsLog.Errorf("error registering external REST subserver: %v",
×
989
                        err)
×
990
        }
×
991
        return nil
3✔
992
}
993

994
// Stop signals any active goroutines for a graceful closure.
995
func (r *rpcServer) Stop() error {
3✔
996
        if atomic.AddInt32(&r.shutdown, 1) != 1 {
3✔
997
                return nil
×
998
        }
×
999

1000
        rpcsLog.Infof("Stopping RPC Server")
3✔
1001

3✔
1002
        close(r.quit)
3✔
1003

3✔
1004
        // After we've signalled all of our active goroutines to exit, we'll
3✔
1005
        // then do the same to signal a graceful shutdown of all the sub
3✔
1006
        // servers.
3✔
1007
        for _, subServer := range r.subServers {
6✔
1008
                rpcsLog.Infof("Stopping %v Sub-RPC Server",
3✔
1009
                        subServer.Name())
3✔
1010

3✔
1011
                if err := subServer.Stop(); err != nil {
3✔
1012
                        rpcsLog.Errorf("unable to stop sub-server %v: %v",
×
1013
                                subServer.Name(), err)
×
1014
                        continue
×
1015
                }
1016
        }
1017

1018
        return nil
3✔
1019
}
1020

1021
// addrPairsToOutputs converts a map describing a set of outputs to be created,
1022
// the outputs themselves. The passed map pairs up an address, to a desired
1023
// output value amount. Each address is converted to its corresponding pkScript
1024
// to be used within the constructed output(s).
1025
func addrPairsToOutputs(addrPairs map[string]int64,
1026
        params *chaincfg.Params) ([]*wire.TxOut, error) {
3✔
1027

3✔
1028
        outputs := make([]*wire.TxOut, 0, len(addrPairs))
3✔
1029
        for addr, amt := range addrPairs {
6✔
1030
                addr, err := btcutil.DecodeAddress(addr, params)
3✔
1031
                if err != nil {
3✔
1032
                        return nil, err
×
1033
                }
×
1034

1035
                if !addr.IsForNet(params) {
3✔
1036
                        return nil, fmt.Errorf("address is not for %s",
×
1037
                                params.Name)
×
1038
                }
×
1039

1040
                pkscript, err := txscript.PayToAddrScript(addr)
3✔
1041
                if err != nil {
3✔
1042
                        return nil, err
×
1043
                }
×
1044

1045
                outputs = append(outputs, wire.NewTxOut(amt, pkscript))
3✔
1046
        }
1047

1048
        return outputs, nil
3✔
1049
}
1050

1051
// allowCORS wraps the given http.Handler with a function that adds the
1052
// Access-Control-Allow-Origin header to the response.
1053
func allowCORS(handler http.Handler, origins []string) http.Handler {
3✔
1054
        allowHeaders := "Access-Control-Allow-Headers"
3✔
1055
        allowMethods := "Access-Control-Allow-Methods"
3✔
1056
        allowOrigin := "Access-Control-Allow-Origin"
3✔
1057

3✔
1058
        // If the user didn't supply any origins that means CORS is disabled
3✔
1059
        // and we should return the original handler.
3✔
1060
        if len(origins) == 0 {
3✔
1061
                return handler
×
1062
        }
×
1063

1064
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
6✔
1065
                origin := r.Header.Get("Origin")
3✔
1066

3✔
1067
                // Skip everything if the browser doesn't send the Origin field.
3✔
1068
                if origin == "" {
6✔
1069
                        handler.ServeHTTP(w, r)
3✔
1070
                        return
3✔
1071
                }
3✔
1072

1073
                // Set the static header fields first.
1074
                w.Header().Set(
3✔
1075
                        allowHeaders,
3✔
1076
                        "Content-Type, Accept, Grpc-Metadata-Macaroon",
3✔
1077
                )
3✔
1078
                w.Header().Set(allowMethods, "GET, POST, DELETE")
3✔
1079

3✔
1080
                // Either we allow all origins or the incoming request matches
3✔
1081
                // a specific origin in our list of allowed origins.
3✔
1082
                for _, allowedOrigin := range origins {
6✔
1083
                        if allowedOrigin == "*" || origin == allowedOrigin {
6✔
1084
                                // Only set allowed origin to requested origin.
3✔
1085
                                w.Header().Set(allowOrigin, origin)
3✔
1086

3✔
1087
                                break
3✔
1088
                        }
1089
                }
1090

1091
                // For a pre-flight request we only need to send the headers
1092
                // back. No need to call the rest of the chain.
1093
                if r.Method == "OPTIONS" {
6✔
1094
                        return
3✔
1095
                }
3✔
1096

1097
                // Everything's prepared now, we can pass the request along the
1098
                // chain of handlers.
1099
                handler.ServeHTTP(w, r)
×
1100
        })
1101
}
1102

1103
// sendCoinsOnChain makes an on-chain transaction in or to send coins to one or
1104
// more addresses specified in the passed payment map. The payment map maps an
1105
// address to a specified output value to be sent to that address.
1106
func (r *rpcServer) sendCoinsOnChain(paymentMap map[string]int64,
1107
        feeRate chainfee.SatPerKWeight, minConfs int32, label string,
1108
        strategy wallet.CoinSelectionStrategy,
1109
        selectedUtxos fn.Set[wire.OutPoint]) (*chainhash.Hash, error) {
3✔
1110

3✔
1111
        outputs, err := addrPairsToOutputs(paymentMap, r.cfg.ActiveNetParams.Params)
3✔
1112
        if err != nil {
3✔
1113
                return nil, err
×
1114
        }
×
1115

1116
        // We first do a dry run, to sanity check we won't spend our wallet
1117
        // balance below the reserved amount.
1118
        authoredTx, err := r.server.cc.Wallet.CreateSimpleTx(
3✔
1119
                selectedUtxos, outputs, feeRate, minConfs, strategy, true,
3✔
1120
        )
3✔
1121
        if err != nil {
6✔
1122
                return nil, err
3✔
1123
        }
3✔
1124

1125
        // Check the authored transaction and use the explicitly set change index
1126
        // to make sure that the wallet reserved balance is not invalidated.
1127
        _, err = r.server.cc.Wallet.CheckReservedValueTx(
3✔
1128
                lnwallet.CheckReservedValueTxReq{
3✔
1129
                        Tx:          authoredTx.Tx,
3✔
1130
                        ChangeIndex: &authoredTx.ChangeIndex,
3✔
1131
                },
3✔
1132
        )
3✔
1133
        if err != nil {
6✔
1134
                return nil, err
3✔
1135
        }
3✔
1136

1137
        // If that checks out, we're fairly confident that creating sending to
1138
        // these outputs will keep the wallet balance above the reserve.
1139
        tx, err := r.server.cc.Wallet.SendOutputs(
3✔
1140
                selectedUtxos, outputs, feeRate, minConfs, label, strategy,
3✔
1141
        )
3✔
1142
        if err != nil {
3✔
1143
                return nil, err
×
1144
        }
×
1145

1146
        txHash := tx.TxHash()
3✔
1147
        return &txHash, nil
3✔
1148
}
1149

1150
// ListUnspent returns useful information about each unspent output owned by
1151
// the wallet, as reported by the underlying `ListUnspentWitness`; the
1152
// information returned is: outpoint, amount in satoshis, address, address
1153
// type, scriptPubKey in hex and number of confirmations.  The result is
1154
// filtered to contain outputs whose number of confirmations is between a
1155
// minimum and maximum number of confirmations specified by the user, with
1156
// 0 meaning unconfirmed.
1157
func (r *rpcServer) ListUnspent(ctx context.Context,
1158
        in *lnrpc.ListUnspentRequest) (*lnrpc.ListUnspentResponse, error) {
×
1159

×
1160
        // Validate the confirmation arguments.
×
1161
        minConfs, maxConfs, err := lnrpc.ParseConfs(in.MinConfs, in.MaxConfs)
×
1162
        if err != nil {
×
1163
                return nil, err
×
1164
        }
×
1165

1166
        // With our arguments validated, we'll query the internal wallet for
1167
        // the set of UTXOs that match our query.
1168
        //
1169
        // We'll acquire the global coin selection lock to ensure there aren't
1170
        // any other concurrent processes attempting to lock any UTXOs which may
1171
        // be shown available to us.
1172
        var utxos []*lnwallet.Utxo
×
1173
        err = r.server.cc.Wallet.WithCoinSelectLock(func() error {
×
1174
                utxos, err = r.server.cc.Wallet.ListUnspentWitness(
×
1175
                        minConfs, maxConfs, in.Account,
×
1176
                )
×
1177
                return err
×
1178
        })
×
1179
        if err != nil {
×
1180
                return nil, err
×
1181
        }
×
1182

1183
        rpcUtxos, err := lnrpc.MarshalUtxos(utxos, r.cfg.ActiveNetParams.Params)
×
1184
        if err != nil {
×
1185
                return nil, err
×
1186
        }
×
1187

1188
        maxStr := ""
×
1189
        if maxConfs != math.MaxInt32 {
×
1190
                maxStr = " max=" + fmt.Sprintf("%d", maxConfs)
×
1191
        }
×
1192

1193
        rpcsLog.Debugf("[listunspent] min=%v%v, generated utxos: %v", minConfs,
×
1194
                maxStr, utxos)
×
1195

×
1196
        return &lnrpc.ListUnspentResponse{
×
1197
                Utxos: rpcUtxos,
×
1198
        }, nil
×
1199
}
1200

1201
// EstimateFee handles a request for estimating the fee for sending a
1202
// transaction spending to multiple specified outputs in parallel.
1203
func (r *rpcServer) EstimateFee(ctx context.Context,
1204
        in *lnrpc.EstimateFeeRequest) (*lnrpc.EstimateFeeResponse, error) {
3✔
1205

3✔
1206
        // Create the list of outputs we are spending to.
3✔
1207
        outputs, err := addrPairsToOutputs(in.AddrToAmount, r.cfg.ActiveNetParams.Params)
3✔
1208
        if err != nil {
3✔
1209
                return nil, err
×
1210
        }
×
1211

1212
        // Query the fee estimator for the fee rate for the given confirmation
1213
        // target.
1214
        target := in.TargetConf
3✔
1215
        feePref := sweep.FeeEstimateInfo{
3✔
1216
                ConfTarget: uint32(target),
3✔
1217
        }
3✔
1218

3✔
1219
        // Since we are providing a fee estimation as an RPC response, there's
3✔
1220
        // no need to set a max feerate here, so we use 0.
3✔
1221
        feePerKw, err := feePref.Estimate(r.server.cc.FeeEstimator, 0)
3✔
1222
        if err != nil {
3✔
1223
                return nil, err
×
1224
        }
×
1225

1226
        // Then, we'll extract the minimum number of confirmations that each
1227
        // output we use to fund the transaction should satisfy.
1228
        minConfs, err := lnrpc.ExtractMinConfs(
3✔
1229
                in.GetMinConfs(), in.GetSpendUnconfirmed(),
3✔
1230
        )
3✔
1231
        if err != nil {
3✔
1232
                return nil, err
×
1233
        }
×
1234

1235
        coinSelectionStrategy, err := lnrpc.UnmarshallCoinSelectionStrategy(
3✔
1236
                in.CoinSelectionStrategy,
3✔
1237
                r.server.cc.Wallet.Cfg.CoinSelectionStrategy,
3✔
1238
        )
3✔
1239
        if err != nil {
3✔
1240
                return nil, err
×
1241
        }
×
1242

1243
        // We will ask the wallet to create a tx using this fee rate. We set
1244
        // dryRun=true to avoid inflating the change addresses in the db.
1245
        var tx *txauthor.AuthoredTx
3✔
1246
        wallet := r.server.cc.Wallet
3✔
1247
        err = wallet.WithCoinSelectLock(func() error {
6✔
1248
                tx, err = wallet.CreateSimpleTx(
3✔
1249
                        nil, outputs, feePerKw, minConfs, coinSelectionStrategy,
3✔
1250
                        true,
3✔
1251
                )
3✔
1252
                return err
3✔
1253
        })
3✔
1254
        if err != nil {
3✔
1255
                return nil, err
×
1256
        }
×
1257

1258
        // Use the created tx to calculate the total fee.
1259
        totalOutput := int64(0)
3✔
1260
        for _, out := range tx.Tx.TxOut {
6✔
1261
                totalOutput += out.Value
3✔
1262
        }
3✔
1263
        totalFee := int64(tx.TotalInput) - totalOutput
3✔
1264

3✔
1265
        resp := &lnrpc.EstimateFeeResponse{
3✔
1266
                FeeSat:      totalFee,
3✔
1267
                SatPerVbyte: uint64(feePerKw.FeePerVByte()),
3✔
1268

3✔
1269
                // Deprecated field.
3✔
1270
                FeerateSatPerByte: int64(feePerKw.FeePerVByte()),
3✔
1271
        }
3✔
1272

3✔
1273
        rpcsLog.Debugf("[estimatefee] fee estimate for conf target %d: %v",
3✔
1274
                target, resp)
3✔
1275

3✔
1276
        return resp, nil
3✔
1277
}
1278

1279
// maybeUseDefaultConf makes sure that when the user doesn't set either the fee
1280
// rate or conf target, the default conf target is used.
1281
func maybeUseDefaultConf(satPerByte int64, satPerVByte uint64,
1282
        targetConf uint32) uint32 {
3✔
1283

3✔
1284
        // If the fee rate is set, there's no need to use the default conf
3✔
1285
        // target. In this case, we just return the targetConf from the
3✔
1286
        // request.
3✔
1287
        if satPerByte != 0 || satPerVByte != 0 {
6✔
1288
                return targetConf
3✔
1289
        }
3✔
1290

1291
        // Return the user specified conf target if set.
1292
        if targetConf != 0 {
6✔
1293
                return targetConf
3✔
1294
        }
3✔
1295

1296
        // If the fee rate is not set, yet the conf target is zero, the default
1297
        // 6 will be returned.
1298
        rpcsLog.Warnf("Expected either 'sat_per_vbyte' or 'conf_target' to " +
3✔
1299
                "be set, using default conf of 6 instead")
3✔
1300

3✔
1301
        return defaultNumBlocksEstimate
3✔
1302
}
1303

1304
// SendCoins executes a request to send coins to a particular address. Unlike
1305
// SendMany, this RPC call only allows creating a single output at a time.
1306
func (r *rpcServer) SendCoins(ctx context.Context,
1307
        in *lnrpc.SendCoinsRequest) (*lnrpc.SendCoinsResponse, error) {
3✔
1308

3✔
1309
        // Keep the old behavior prior to 0.18.0 - when the user doesn't set
3✔
1310
        // fee rate or conf target, the default conf target of 6 is used.
3✔
1311
        targetConf := maybeUseDefaultConf(
3✔
1312
                in.SatPerByte, in.SatPerVbyte, uint32(in.TargetConf),
3✔
1313
        )
3✔
1314

3✔
1315
        // Calculate an appropriate fee rate for this transaction.
3✔
1316
        feePerKw, err := lnrpc.CalculateFeeRate(
3✔
1317
                uint64(in.SatPerByte), in.SatPerVbyte, // nolint:staticcheck
3✔
1318
                targetConf, r.server.cc.FeeEstimator,
3✔
1319
        )
3✔
1320
        if err != nil {
3✔
1321
                return nil, err
×
1322
        }
×
1323

1324
        // Then, we'll extract the minimum number of confirmations that each
1325
        // output we use to fund the transaction should satisfy.
1326
        minConfs, err := lnrpc.ExtractMinConfs(in.MinConfs, in.SpendUnconfirmed)
3✔
1327
        if err != nil {
3✔
1328
                return nil, err
×
1329
        }
×
1330

1331
        rpcsLog.Infof("[sendcoins] addr=%v, amt=%v, sat/kw=%v, min_confs=%v, "+
3✔
1332
                "send_all=%v, select_outpoints=%v",
3✔
1333
                in.Addr, btcutil.Amount(in.Amount), int64(feePerKw), minConfs,
3✔
1334
                in.SendAll, len(in.Outpoints))
3✔
1335

3✔
1336
        // Decode the address receiving the coins, we need to check whether the
3✔
1337
        // address is valid for this network.
3✔
1338
        targetAddr, err := btcutil.DecodeAddress(
3✔
1339
                in.Addr, r.cfg.ActiveNetParams.Params,
3✔
1340
        )
3✔
1341
        if err != nil {
6✔
1342
                return nil, err
3✔
1343
        }
3✔
1344

1345
        // Make the check on the decoded address according to the active network.
1346
        if !targetAddr.IsForNet(r.cfg.ActiveNetParams.Params) {
6✔
1347
                return nil, fmt.Errorf("address: %v is not valid for this "+
3✔
1348
                        "network: %v", targetAddr.String(),
3✔
1349
                        r.cfg.ActiveNetParams.Params.Name)
3✔
1350
        }
3✔
1351

1352
        // If the destination address parses to a valid pubkey, we assume the user
1353
        // accidentally tried to send funds to a bare pubkey address. This check is
1354
        // here to prevent unintended transfers.
1355
        decodedAddr, _ := hex.DecodeString(in.Addr)
3✔
1356
        _, err = btcec.ParsePubKey(decodedAddr)
3✔
1357
        if err == nil {
6✔
1358
                return nil, fmt.Errorf("cannot send coins to pubkeys")
3✔
1359
        }
3✔
1360

1361
        label, err := labels.ValidateAPI(in.Label)
3✔
1362
        if err != nil {
3✔
1363
                return nil, err
×
1364
        }
×
1365

1366
        coinSelectionStrategy, err := lnrpc.UnmarshallCoinSelectionStrategy(
3✔
1367
                in.CoinSelectionStrategy,
3✔
1368
                r.server.cc.Wallet.Cfg.CoinSelectionStrategy,
3✔
1369
        )
3✔
1370
        if err != nil {
3✔
1371
                return nil, err
×
1372
        }
×
1373

1374
        var txid *chainhash.Hash
3✔
1375

3✔
1376
        wallet := r.server.cc.Wallet
3✔
1377
        maxFeeRate := r.cfg.Sweeper.MaxFeeRate.FeePerKWeight()
3✔
1378

3✔
1379
        var selectOutpoints fn.Set[wire.OutPoint]
3✔
1380
        if len(in.Outpoints) != 0 {
6✔
1381
                wireOutpoints, err := toWireOutpoints(in.Outpoints)
3✔
1382
                if err != nil {
3✔
1383
                        return nil, fmt.Errorf("can't create outpoints "+
×
1384
                                "%w", err)
×
1385
                }
×
1386

1387
                if fn.HasDuplicates(wireOutpoints) {
6✔
1388
                        return nil, fmt.Errorf("selected outpoints contain " +
3✔
1389
                                "duplicate values")
3✔
1390
                }
3✔
1391

1392
                selectOutpoints = fn.NewSet(wireOutpoints...)
3✔
1393
        }
1394

1395
        // If the send all flag is active, then we'll attempt to sweep all the
1396
        // coins in the wallet in a single transaction (if possible),
1397
        // otherwise, we'll respect the amount, and attempt a regular 2-output
1398
        // send.
1399
        if in.SendAll {
6✔
1400
                // At this point, the amount shouldn't be set since we've been
3✔
1401
                // instructed to sweep all the coins from the wallet.
3✔
1402
                if in.Amount != 0 {
6✔
1403
                        return nil, fmt.Errorf("amount set while SendAll is " +
3✔
1404
                                "active")
3✔
1405
                }
3✔
1406

1407
                _, bestHeight, err := r.server.cc.ChainIO.GetBestBlock()
3✔
1408
                if err != nil {
3✔
1409
                        return nil, err
×
1410
                }
×
1411

1412
                // With the sweeper instance created, we can now generate a
1413
                // transaction that will sweep ALL outputs from the wallet in a
1414
                // single transaction. This will be generated in a concurrent
1415
                // safe manner, so no need to worry about locking. The tx will
1416
                // pay to the change address created above if we needed to
1417
                // reserve any value, the rest will go to targetAddr.
1418
                sweepTxPkg, err := sweep.CraftSweepAllTx(
3✔
1419
                        feePerKw, maxFeeRate, uint32(bestHeight), nil,
3✔
1420
                        targetAddr, wallet, wallet, wallet.WalletController,
3✔
1421
                        r.server.cc.Signer, minConfs, selectOutpoints,
3✔
1422
                )
3✔
1423
                if err != nil {
3✔
1424
                        return nil, err
×
1425
                }
×
1426

1427
                // Before we publish the transaction we make sure it won't
1428
                // violate our reserved wallet value.
1429
                var reservedVal btcutil.Amount
3✔
1430
                err = wallet.WithCoinSelectLock(func() error {
6✔
1431
                        var err error
3✔
1432
                        reservedVal, err = wallet.CheckReservedValueTx(
3✔
1433
                                lnwallet.CheckReservedValueTxReq{
3✔
1434
                                        Tx: sweepTxPkg.SweepTx,
3✔
1435
                                },
3✔
1436
                        )
3✔
1437
                        return err
3✔
1438
                })
3✔
1439

1440
                // If sending everything to this address would invalidate our
1441
                // reserved wallet balance, we create a new sweep tx, where
1442
                // we'll send the reserved value back to our wallet.
1443
                if err == lnwallet.ErrReservedValueInvalidated {
6✔
1444
                        sweepTxPkg.CancelSweepAttempt()
3✔
1445

3✔
1446
                        rpcsLog.Debugf("Reserved value %v not satisfied after "+
3✔
1447
                                "send_all, trying with change output",
3✔
1448
                                reservedVal)
3✔
1449

3✔
1450
                        // We'll request a change address from the wallet,
3✔
1451
                        // where we'll send this reserved value back to. This
3✔
1452
                        // ensures this is an address the wallet knows about,
3✔
1453
                        // allowing us to pass the reserved value check.
3✔
1454
                        changeAddr, err := r.server.cc.Wallet.NewAddress(
3✔
1455
                                lnwallet.TaprootPubkey, true,
3✔
1456
                                lnwallet.DefaultAccountName,
3✔
1457
                        )
3✔
1458
                        if err != nil {
3✔
1459
                                return nil, err
×
1460
                        }
×
1461

1462
                        // Send the reserved value to this change address, the
1463
                        // remaining funds will go to the targetAddr.
1464
                        outputs := []sweep.DeliveryAddr{
3✔
1465
                                {
3✔
1466
                                        Addr: changeAddr,
3✔
1467
                                        Amt:  reservedVal,
3✔
1468
                                },
3✔
1469
                        }
3✔
1470

3✔
1471
                        sweepTxPkg, err = sweep.CraftSweepAllTx(
3✔
1472
                                feePerKw, maxFeeRate, uint32(bestHeight),
3✔
1473
                                outputs, targetAddr, wallet, wallet,
3✔
1474
                                wallet.WalletController,
3✔
1475
                                r.server.cc.Signer, minConfs, selectOutpoints,
3✔
1476
                        )
3✔
1477
                        if err != nil {
3✔
1478
                                return nil, err
×
1479
                        }
×
1480

1481
                        // Sanity check the new tx by re-doing the check.
1482
                        err = wallet.WithCoinSelectLock(func() error {
6✔
1483
                                _, err := wallet.CheckReservedValueTx(
3✔
1484
                                        lnwallet.CheckReservedValueTxReq{
3✔
1485
                                                Tx: sweepTxPkg.SweepTx,
3✔
1486
                                        },
3✔
1487
                                )
3✔
1488
                                return err
3✔
1489
                        })
3✔
1490
                        if err != nil {
3✔
1491
                                sweepTxPkg.CancelSweepAttempt()
×
1492

×
1493
                                return nil, err
×
1494
                        }
×
1495
                } else if err != nil {
3✔
1496
                        sweepTxPkg.CancelSweepAttempt()
×
1497

×
1498
                        return nil, err
×
1499
                }
×
1500

1501
                rpcsLog.Debugf("Sweeping coins from wallet to addr=%v, "+
3✔
1502
                        "with tx=%v", in.Addr, spew.Sdump(sweepTxPkg.SweepTx))
3✔
1503

3✔
1504
                // As our sweep transaction was created, successfully, we'll
3✔
1505
                // now attempt to publish it, cancelling the sweep pkg to
3✔
1506
                // return all outputs if it fails.
3✔
1507
                err = wallet.PublishTransaction(sweepTxPkg.SweepTx, label)
3✔
1508
                if err != nil {
3✔
1509
                        sweepTxPkg.CancelSweepAttempt()
×
1510

×
1511
                        return nil, fmt.Errorf("unable to broadcast sweep "+
×
1512
                                "transaction: %v", err)
×
1513
                }
×
1514

1515
                sweepTXID := sweepTxPkg.SweepTx.TxHash()
3✔
1516
                txid = &sweepTXID
3✔
1517
        } else {
3✔
1518

3✔
1519
                // We'll now construct out payment map, and use the wallet's
3✔
1520
                // coin selection synchronization method to ensure that no coin
3✔
1521
                // selection (funding, sweep alls, other sends) can proceed
3✔
1522
                // while we instruct the wallet to send this transaction.
3✔
1523
                paymentMap := map[string]int64{targetAddr.String(): in.Amount}
3✔
1524
                err := wallet.WithCoinSelectLock(func() error {
6✔
1525
                        newTXID, err := r.sendCoinsOnChain(
3✔
1526
                                paymentMap, feePerKw, minConfs, label,
3✔
1527
                                coinSelectionStrategy, selectOutpoints,
3✔
1528
                        )
3✔
1529
                        if err != nil {
6✔
1530
                                return err
3✔
1531
                        }
3✔
1532

1533
                        txid = newTXID
3✔
1534

3✔
1535
                        return nil
3✔
1536
                })
1537
                if err != nil {
6✔
1538
                        return nil, err
3✔
1539
                }
3✔
1540
        }
1541

1542
        rpcsLog.Infof("[sendcoins] spend generated txid: %v", txid.String())
3✔
1543

3✔
1544
        return &lnrpc.SendCoinsResponse{Txid: txid.String()}, nil
3✔
1545
}
1546

1547
// SendMany handles a request for a transaction create multiple specified
1548
// outputs in parallel.
1549
func (r *rpcServer) SendMany(ctx context.Context,
1550
        in *lnrpc.SendManyRequest) (*lnrpc.SendManyResponse, error) {
×
1551

×
1552
        // Keep the old behavior prior to 0.18.0 - when the user doesn't set
×
1553
        // fee rate or conf target, the default conf target of 6 is used.
×
1554
        targetConf := maybeUseDefaultConf(
×
1555
                in.SatPerByte, in.SatPerVbyte, uint32(in.TargetConf),
×
1556
        )
×
1557

×
1558
        // Calculate an appropriate fee rate for this transaction.
×
1559
        feePerKw, err := lnrpc.CalculateFeeRate(
×
1560
                uint64(in.SatPerByte), in.SatPerVbyte, // nolint:staticcheck
×
1561
                targetConf, r.server.cc.FeeEstimator,
×
1562
        )
×
1563
        if err != nil {
×
1564
                return nil, err
×
1565
        }
×
1566

1567
        // Then, we'll extract the minimum number of confirmations that each
1568
        // output we use to fund the transaction should satisfy.
1569
        minConfs, err := lnrpc.ExtractMinConfs(in.MinConfs, in.SpendUnconfirmed)
×
1570
        if err != nil {
×
1571
                return nil, err
×
1572
        }
×
1573

1574
        label, err := labels.ValidateAPI(in.Label)
×
1575
        if err != nil {
×
1576
                return nil, err
×
1577
        }
×
1578

1579
        coinSelectionStrategy, err := lnrpc.UnmarshallCoinSelectionStrategy(
×
1580
                in.CoinSelectionStrategy,
×
1581
                r.server.cc.Wallet.Cfg.CoinSelectionStrategy,
×
1582
        )
×
1583
        if err != nil {
×
1584
                return nil, err
×
1585
        }
×
1586

1587
        rpcsLog.Infof("[sendmany] outputs=%v, sat/kw=%v",
×
1588
                spew.Sdump(in.AddrToAmount), int64(feePerKw))
×
1589

×
1590
        var txid *chainhash.Hash
×
1591

×
1592
        // We'll attempt to send to the target set of outputs, ensuring that we
×
1593
        // synchronize with any other ongoing coin selection attempts which
×
1594
        // happen to also be concurrently executing.
×
1595
        wallet := r.server.cc.Wallet
×
1596
        err = wallet.WithCoinSelectLock(func() error {
×
1597
                sendManyTXID, err := r.sendCoinsOnChain(
×
1598
                        in.AddrToAmount, feePerKw, minConfs, label,
×
1599
                        coinSelectionStrategy, nil,
×
1600
                )
×
1601
                if err != nil {
×
1602
                        return err
×
1603
                }
×
1604

1605
                txid = sendManyTXID
×
1606

×
1607
                return nil
×
1608
        })
1609
        if err != nil {
×
1610
                return nil, err
×
1611
        }
×
1612

1613
        rpcsLog.Infof("[sendmany] spend generated txid: %v", txid.String())
×
1614

×
1615
        return &lnrpc.SendManyResponse{Txid: txid.String()}, nil
×
1616
}
1617

1618
// NewAddress creates a new address under control of the local wallet.
1619
func (r *rpcServer) NewAddress(ctx context.Context,
1620
        in *lnrpc.NewAddressRequest) (*lnrpc.NewAddressResponse, error) {
3✔
1621

3✔
1622
        // Always use the default wallet account unless one was specified.
3✔
1623
        account := lnwallet.DefaultAccountName
3✔
1624
        if in.Account != "" {
6✔
1625
                account = in.Account
3✔
1626
        }
3✔
1627

1628
        // Translate the gRPC proto address type to the wallet controller's
1629
        // available address types.
1630
        var (
3✔
1631
                addr btcutil.Address
3✔
1632
                err  error
3✔
1633
        )
3✔
1634
        switch in.Type {
3✔
1635
        case lnrpc.AddressType_WITNESS_PUBKEY_HASH:
3✔
1636
                addr, err = r.server.cc.Wallet.NewAddress(
3✔
1637
                        lnwallet.WitnessPubKey, false, account,
3✔
1638
                )
3✔
1639
                if err != nil {
3✔
1640
                        return nil, err
×
1641
                }
×
1642

1643
        case lnrpc.AddressType_NESTED_PUBKEY_HASH:
3✔
1644
                addr, err = r.server.cc.Wallet.NewAddress(
3✔
1645
                        lnwallet.NestedWitnessPubKey, false, account,
3✔
1646
                )
3✔
1647
                if err != nil {
3✔
1648
                        return nil, err
×
1649
                }
×
1650

1651
        case lnrpc.AddressType_TAPROOT_PUBKEY:
3✔
1652
                addr, err = r.server.cc.Wallet.NewAddress(
3✔
1653
                        lnwallet.TaprootPubkey, false, account,
3✔
1654
                )
3✔
1655
                if err != nil {
3✔
1656
                        return nil, err
×
1657
                }
×
1658

1659
        case lnrpc.AddressType_UNUSED_WITNESS_PUBKEY_HASH:
3✔
1660
                addr, err = r.server.cc.Wallet.LastUnusedAddress(
3✔
1661
                        lnwallet.WitnessPubKey, account,
3✔
1662
                )
3✔
1663
                if err != nil {
3✔
1664
                        return nil, err
×
1665
                }
×
1666

1667
        case lnrpc.AddressType_UNUSED_NESTED_PUBKEY_HASH:
×
1668
                addr, err = r.server.cc.Wallet.LastUnusedAddress(
×
1669
                        lnwallet.NestedWitnessPubKey, account,
×
1670
                )
×
1671
                if err != nil {
×
1672
                        return nil, err
×
1673
                }
×
1674

1675
        case lnrpc.AddressType_UNUSED_TAPROOT_PUBKEY:
3✔
1676
                addr, err = r.server.cc.Wallet.LastUnusedAddress(
3✔
1677
                        lnwallet.TaprootPubkey, account,
3✔
1678
                )
3✔
1679
                if err != nil {
3✔
1680
                        return nil, err
×
1681
                }
×
1682

1683
        default:
×
1684
                return nil, fmt.Errorf("unknown address type: %v", in.Type)
×
1685
        }
1686

1687
        rpcsLog.Debugf("[newaddress] account=%v type=%v addr=%v", account,
3✔
1688
                in.Type, addr.String())
3✔
1689
        return &lnrpc.NewAddressResponse{Address: addr.String()}, nil
3✔
1690
}
1691

1692
var (
1693
        // signedMsgPrefix is a special prefix that we'll prepend to any
1694
        // messages we sign/verify. We do this to ensure that we don't
1695
        // accidentally sign a sighash, or other sensitive material. By
1696
        // prepending this fragment, we mind message signing to our particular
1697
        // context.
1698
        signedMsgPrefix = []byte("Lightning Signed Message:")
1699
)
1700

1701
// SignMessage signs a message with the resident node's private key. The
1702
// returned signature string is zbase32 encoded and pubkey recoverable, meaning
1703
// that only the message digest and signature are needed for verification.
1704
func (r *rpcServer) SignMessage(_ context.Context,
1705
        in *lnrpc.SignMessageRequest) (*lnrpc.SignMessageResponse, error) {
3✔
1706

3✔
1707
        if in.Msg == nil {
3✔
1708
                return nil, fmt.Errorf("need a message to sign")
×
1709
        }
×
1710

1711
        in.Msg = append(signedMsgPrefix, in.Msg...)
3✔
1712
        sigBytes, err := r.server.nodeSigner.SignMessageCompact(
3✔
1713
                in.Msg, !in.SingleHash,
3✔
1714
        )
3✔
1715
        if err != nil {
3✔
1716
                return nil, err
×
1717
        }
×
1718

1719
        sig := zbase32.EncodeToString(sigBytes)
3✔
1720
        return &lnrpc.SignMessageResponse{Signature: sig}, nil
3✔
1721
}
1722

1723
// VerifyMessage verifies a signature over a msg. The signature must be zbase32
1724
// encoded and signed by an active node in the resident node's channel
1725
// database. In addition to returning the validity of the signature,
1726
// VerifyMessage also returns the recovered pubkey from the signature.
1727
func (r *rpcServer) VerifyMessage(ctx context.Context,
1728
        in *lnrpc.VerifyMessageRequest) (*lnrpc.VerifyMessageResponse, error) {
3✔
1729

3✔
1730
        if in.Msg == nil {
3✔
1731
                return nil, fmt.Errorf("need a message to verify")
×
1732
        }
×
1733

1734
        // The signature should be zbase32 encoded
1735
        sig, err := zbase32.DecodeString(in.Signature)
3✔
1736
        if err != nil {
3✔
1737
                return nil, fmt.Errorf("failed to decode signature: %w", err)
×
1738
        }
×
1739

1740
        // The signature is over the double-sha256 hash of the message.
1741
        in.Msg = append(signedMsgPrefix, in.Msg...)
3✔
1742
        digest := chainhash.DoubleHashB(in.Msg)
3✔
1743

3✔
1744
        // RecoverCompact both recovers the pubkey and validates the signature.
3✔
1745
        pubKey, _, err := ecdsa.RecoverCompact(sig, digest)
3✔
1746
        if err != nil {
3✔
1747
                return &lnrpc.VerifyMessageResponse{Valid: false}, nil
×
1748
        }
×
1749
        pubKeyHex := hex.EncodeToString(pubKey.SerializeCompressed())
3✔
1750

3✔
1751
        var pub [33]byte
3✔
1752
        copy(pub[:], pubKey.SerializeCompressed())
3✔
1753

3✔
1754
        // Query the channel graph to ensure a node in the network with active
3✔
1755
        // channels signed the message.
3✔
1756
        //
3✔
1757
        // TODO(phlip9): Require valid nodes to have capital in active channels.
3✔
1758
        graph := r.server.graphDB
3✔
1759
        _, active, err := graph.HasLightningNode(pub)
3✔
1760
        if err != nil {
3✔
1761
                return nil, fmt.Errorf("failed to query graph: %w", err)
×
1762
        }
×
1763

1764
        return &lnrpc.VerifyMessageResponse{
3✔
1765
                Valid:  active,
3✔
1766
                Pubkey: pubKeyHex,
3✔
1767
        }, nil
3✔
1768
}
1769

1770
// ConnectPeer attempts to establish a connection to a remote peer.
1771
func (r *rpcServer) ConnectPeer(ctx context.Context,
1772
        in *lnrpc.ConnectPeerRequest) (*lnrpc.ConnectPeerResponse, error) {
3✔
1773

3✔
1774
        // The server hasn't yet started, so it won't be able to service any of
3✔
1775
        // our requests, so we'll bail early here.
3✔
1776
        if !r.server.Started() {
3✔
1777
                return nil, ErrServerNotActive
×
1778
        }
×
1779

1780
        if in.Addr == nil {
3✔
1781
                return nil, fmt.Errorf("need: lnc pubkeyhash@hostname")
×
1782
        }
×
1783

1784
        pubkeyHex, err := hex.DecodeString(in.Addr.Pubkey)
3✔
1785
        if err != nil {
3✔
1786
                return nil, err
×
1787
        }
×
1788
        pubKey, err := btcec.ParsePubKey(pubkeyHex)
3✔
1789
        if err != nil {
3✔
1790
                return nil, err
×
1791
        }
×
1792

1793
        // Connections to ourselves are disallowed for obvious reasons.
1794
        if pubKey.IsEqual(r.server.identityECDH.PubKey()) {
3✔
1795
                return nil, fmt.Errorf("cannot make connection to self")
×
1796
        }
×
1797

1798
        addr, err := parseAddr(in.Addr.Host, r.cfg.net)
3✔
1799
        if err != nil {
3✔
1800
                return nil, err
×
1801
        }
×
1802

1803
        peerAddr := &lnwire.NetAddress{
3✔
1804
                IdentityKey: pubKey,
3✔
1805
                Address:     addr,
3✔
1806
                ChainNet:    r.cfg.ActiveNetParams.Net,
3✔
1807
        }
3✔
1808

3✔
1809
        rpcsLog.Debugf("[connectpeer] requested connection to %x@%s",
3✔
1810
                peerAddr.IdentityKey.SerializeCompressed(), peerAddr.Address)
3✔
1811

3✔
1812
        // By default, we will use the global connection timeout value.
3✔
1813
        timeout := r.cfg.ConnectionTimeout
3✔
1814

3✔
1815
        // Check if the connection timeout is set. If set, we will use it in our
3✔
1816
        // request.
3✔
1817
        if in.Timeout != 0 {
6✔
1818
                timeout = time.Duration(in.Timeout) * time.Second
3✔
1819
                rpcsLog.Debugf("[connectpeer] connection timeout is set to %v",
3✔
1820
                        timeout)
3✔
1821
        }
3✔
1822

1823
        if err := r.server.ConnectToPeer(
3✔
1824
                peerAddr, in.Perm, timeout,
3✔
1825
        ); err != nil {
6✔
1826
                rpcsLog.Errorf("[connectpeer]: error connecting to peer: %v",
3✔
1827
                        err)
3✔
1828
                return nil, err
3✔
1829
        }
3✔
1830

1831
        rpcsLog.Debugf("Connected to peer: %v", peerAddr.String())
3✔
1832

3✔
1833
        return &lnrpc.ConnectPeerResponse{
3✔
1834
                Status: fmt.Sprintf("connection to %v initiated",
3✔
1835
                        peerAddr.String()),
3✔
1836
        }, nil
3✔
1837
}
1838

1839
// DisconnectPeer attempts to disconnect one peer from another identified by a
1840
// given pubKey. In the case that we currently have a pending or active channel
1841
// with the target peer, this action will be disallowed.
1842
func (r *rpcServer) DisconnectPeer(ctx context.Context,
1843
        in *lnrpc.DisconnectPeerRequest) (*lnrpc.DisconnectPeerResponse, error) {
3✔
1844

3✔
1845
        rpcsLog.Debugf("[disconnectpeer] from peer(%s)", in.PubKey)
3✔
1846

3✔
1847
        if !r.server.Started() {
3✔
1848
                return nil, ErrServerNotActive
×
1849
        }
×
1850

1851
        // First we'll validate the string passed in within the request to
1852
        // ensure that it's a valid hex-string, and also a valid compressed
1853
        // public key.
1854
        pubKeyBytes, err := hex.DecodeString(in.PubKey)
3✔
1855
        if err != nil {
3✔
1856
                return nil, fmt.Errorf("unable to decode pubkey bytes: %w", err)
×
1857
        }
×
1858
        peerPubKey, err := btcec.ParsePubKey(pubKeyBytes)
3✔
1859
        if err != nil {
3✔
1860
                return nil, fmt.Errorf("unable to parse pubkey: %w", err)
×
1861
        }
×
1862

1863
        // Next, we'll fetch the pending/active channels we have with a
1864
        // particular peer.
1865
        nodeChannels, err := r.server.chanStateDB.FetchOpenChannels(peerPubKey)
3✔
1866
        if err != nil {
3✔
1867
                return nil, fmt.Errorf("unable to fetch channels for peer: %w",
×
1868
                        err)
×
1869
        }
×
1870

1871
        // In order to avoid erroneously disconnecting from a peer that we have
1872
        // an active channel with, if we have any channels active with this
1873
        // peer, then we'll disallow disconnecting from them.
1874
        if len(nodeChannels) != 0 {
6✔
1875
                // If we are not in a dev environment or the configed dev value
3✔
1876
                // `unsafedisconnect` is false, we return an error since there
3✔
1877
                // are active channels.
3✔
1878
                if !r.cfg.Dev.GetUnsafeDisconnect() {
3✔
1879
                        return nil, fmt.Errorf("cannot disconnect from "+
×
1880
                                "peer(%x), still has %d active channels",
×
1881
                                pubKeyBytes, len(nodeChannels))
×
1882
                }
×
1883

1884
                // We are in a dev environment, print a warning log and
1885
                // disconnect.
1886
                rpcsLog.Warnf("UnsafeDisconnect mode, disconnecting from "+
3✔
1887
                        "peer(%x) while there are %d active channels",
3✔
1888
                        pubKeyBytes, len(nodeChannels))
3✔
1889
        }
1890

1891
        // With all initial validation complete, we'll now request that the
1892
        // server disconnects from the peer.
1893
        err = r.server.DisconnectPeer(peerPubKey)
3✔
1894
        if err != nil {
3✔
1895
                return nil, fmt.Errorf("unable to disconnect peer: %w", err)
×
1896
        }
×
1897

1898
        return &lnrpc.DisconnectPeerResponse{
3✔
1899
                Status: "disconnect initiated",
3✔
1900
        }, nil
3✔
1901
}
1902

1903
// newFundingShimAssembler returns a new fully populated
1904
// chanfunding.CannedAssembler using a FundingShim obtained from an RPC caller.
1905
func newFundingShimAssembler(chanPointShim *lnrpc.ChanPointShim, initiator bool,
1906
        keyRing keychain.KeyRing) (chanfunding.Assembler, error) {
3✔
1907

3✔
1908
        // Perform some basic sanity checks to ensure that all the expected
3✔
1909
        // fields are populated.
3✔
1910
        switch {
3✔
1911
        case chanPointShim.RemoteKey == nil:
×
1912
                return nil, fmt.Errorf("remote key not set")
×
1913

1914
        case chanPointShim.LocalKey == nil:
×
1915
                return nil, fmt.Errorf("local key desc not set")
×
1916

1917
        case chanPointShim.LocalKey.RawKeyBytes == nil:
×
1918
                return nil, fmt.Errorf("local raw key bytes not set")
×
1919

1920
        case chanPointShim.LocalKey.KeyLoc == nil:
×
1921
                return nil, fmt.Errorf("local key loc not set")
×
1922

1923
        case chanPointShim.ChanPoint == nil:
×
1924
                return nil, fmt.Errorf("chan point not set")
×
1925

1926
        case len(chanPointShim.PendingChanId) != 32:
×
1927
                return nil, fmt.Errorf("pending chan ID not set")
×
1928
        }
1929

1930
        // First, we'll map the RPC's channel point to one we can actually use.
1931
        index := chanPointShim.ChanPoint.OutputIndex
3✔
1932
        txid, err := lnrpc.GetChanPointFundingTxid(chanPointShim.ChanPoint)
3✔
1933
        if err != nil {
3✔
1934
                return nil, err
×
1935
        }
×
1936
        chanPoint := wire.NewOutPoint(txid, index)
3✔
1937

3✔
1938
        // Next we'll parse out the remote party's funding key, as well as our
3✔
1939
        // full key descriptor.
3✔
1940
        remoteKey, err := btcec.ParsePubKey(chanPointShim.RemoteKey)
3✔
1941
        if err != nil {
3✔
1942
                return nil, err
×
1943
        }
×
1944

1945
        shimKeyDesc := chanPointShim.LocalKey
3✔
1946
        localKey, err := btcec.ParsePubKey(shimKeyDesc.RawKeyBytes)
3✔
1947
        if err != nil {
3✔
1948
                return nil, err
×
1949
        }
×
1950
        localKeyDesc := keychain.KeyDescriptor{
3✔
1951
                PubKey: localKey,
3✔
1952
                KeyLocator: keychain.KeyLocator{
3✔
1953
                        Family: keychain.KeyFamily(
3✔
1954
                                shimKeyDesc.KeyLoc.KeyFamily,
3✔
1955
                        ),
3✔
1956
                        Index: uint32(shimKeyDesc.KeyLoc.KeyIndex),
3✔
1957
                },
3✔
1958
        }
3✔
1959

3✔
1960
        // Verify that if we re-derive this key according to the passed
3✔
1961
        // KeyLocator, that we get the exact same key back. Otherwise, we may
3✔
1962
        // end up in a situation where we aren't able to actually sign for this
3✔
1963
        // newly created channel.
3✔
1964
        derivedKey, err := keyRing.DeriveKey(localKeyDesc.KeyLocator)
3✔
1965
        if err != nil {
3✔
1966
                return nil, err
×
1967
        }
×
1968
        if !derivedKey.PubKey.IsEqual(localKey) {
3✔
1969
                return nil, fmt.Errorf("KeyLocator does not match attached " +
×
1970
                        "raw pubkey")
×
1971
        }
×
1972

1973
        // With all the parts assembled, we can now make the canned assembler
1974
        // to pass into the wallet.
1975
        //
1976
        // TODO(roasbeef): update to support musig2
1977
        return chanfunding.NewCannedAssembler(
3✔
1978
                chanPointShim.ThawHeight, *chanPoint,
3✔
1979
                btcutil.Amount(chanPointShim.Amt), &localKeyDesc,
3✔
1980
                remoteKey, initiator, chanPointShim.Musig2,
3✔
1981
        ), nil
3✔
1982
}
1983

1984
// newPsbtAssembler returns a new fully populated
1985
// chanfunding.PsbtAssembler using a FundingShim obtained from an RPC caller.
1986
func newPsbtAssembler(req *lnrpc.OpenChannelRequest,
1987
        psbtShim *lnrpc.PsbtShim, netParams *chaincfg.Params) (
1988
        chanfunding.Assembler, error) {
3✔
1989

3✔
1990
        var (
3✔
1991
                packet *psbt.Packet
3✔
1992
                err    error
3✔
1993
        )
3✔
1994

3✔
1995
        // Perform some basic sanity checks to ensure that all the expected
3✔
1996
        // fields are populated and none of the incompatible fields are.
3✔
1997
        if len(psbtShim.PendingChanId) != 32 {
3✔
1998
                return nil, fmt.Errorf("pending chan ID not set")
×
1999
        }
×
2000
        if req.SatPerByte != 0 || req.SatPerVbyte != 0 || req.TargetConf != 0 { // nolint:staticcheck
3✔
2001
                return nil, fmt.Errorf("specifying fee estimation parameters " +
×
2002
                        "is not supported for PSBT funding")
×
2003
        }
×
2004

2005
        // The base PSBT is optional. But if it's set, it has to be a valid,
2006
        // binary serialized PSBT.
2007
        if len(psbtShim.BasePsbt) > 0 {
6✔
2008
                packet, err = psbt.NewFromRawBytes(
3✔
2009
                        bytes.NewReader(psbtShim.BasePsbt), false,
3✔
2010
                )
3✔
2011
                if err != nil {
3✔
2012
                        return nil, fmt.Errorf("error parsing base PSBT: %w",
×
2013
                                err)
×
2014
                }
×
2015
        }
2016

2017
        // With all the parts assembled, we can now make the canned assembler
2018
        // to pass into the wallet.
2019
        return chanfunding.NewPsbtAssembler(
3✔
2020
                btcutil.Amount(req.LocalFundingAmount), packet, netParams,
3✔
2021
                !psbtShim.NoPublish,
3✔
2022
        ), nil
3✔
2023
}
2024

2025
// canOpenChannel returns an error if the necessary subsystems for channel
2026
// funding are not ready.
2027
func (r *rpcServer) canOpenChannel() error {
3✔
2028
        // We can't open a channel until the main server has started.
3✔
2029
        if !r.server.Started() {
3✔
2030
                return ErrServerNotActive
×
2031
        }
×
2032

2033
        // Creation of channels before the wallet syncs up is currently
2034
        // disallowed.
2035
        isSynced, _, err := r.server.cc.Wallet.IsSynced()
3✔
2036
        if err != nil {
3✔
2037
                return err
×
2038
        }
×
2039
        if !isSynced {
3✔
2040
                return errors.New("channels cannot be created before the " +
×
2041
                        "wallet is fully synced")
×
2042
        }
×
2043

2044
        return nil
3✔
2045
}
2046

2047
// parseOpenChannelReq parses an OpenChannelRequest message into an InitFundingMsg
2048
// struct. The logic is abstracted so that it can be shared between OpenChannel
2049
// and OpenChannelSync.
2050
func (r *rpcServer) parseOpenChannelReq(in *lnrpc.OpenChannelRequest,
2051
        isSync bool) (*funding.InitFundingMsg, error) {
3✔
2052

3✔
2053
        rpcsLog.Debugf("[openchannel] request to NodeKey(%x) "+
3✔
2054
                "allocation(us=%v, them=%v)", in.NodePubkey,
3✔
2055
                in.LocalFundingAmount, in.PushSat)
3✔
2056

3✔
2057
        localFundingAmt := btcutil.Amount(in.LocalFundingAmount)
3✔
2058
        remoteInitialBalance := btcutil.Amount(in.PushSat)
3✔
2059

3✔
2060
        // If we are not committing the maximum viable balance towards a channel
3✔
2061
        // then the local funding amount must be specified. In case FundMax is
3✔
2062
        // set the funding amount is specified as the interval between minimum
3✔
2063
        // funding amount and by the configured maximum channel size.
3✔
2064
        if !in.FundMax && localFundingAmt == 0 {
3✔
2065
                return nil, fmt.Errorf("local funding amount must be non-zero")
×
2066
        }
×
2067

2068
        // Ensure that the initial balance of the remote party (if pushing
2069
        // satoshis) does not exceed the amount the local party has requested
2070
        // for funding. This is only checked if we are not committing the
2071
        // maximum viable amount towards the channel balance. If we do commit
2072
        // the maximum then the remote balance is checked in a dedicated FundMax
2073
        // check.
2074
        if !in.FundMax && remoteInitialBalance >= localFundingAmt {
3✔
2075
                return nil, fmt.Errorf("amount pushed to remote peer for " +
×
2076
                        "initial state must be below the local funding amount")
×
2077
        }
×
2078

2079
        // We either allow the fundmax or the psbt flow hence we return an error
2080
        // if both are set.
2081
        if in.FundingShim != nil && in.FundMax {
3✔
2082
                return nil, fmt.Errorf("cannot provide a psbt funding shim " +
×
2083
                        "while committing the maximum wallet balance towards " +
×
2084
                        "the channel opening")
×
2085
        }
×
2086

2087
        // If the FundMax flag is set, ensure that the acceptable minimum local
2088
        // amount adheres to the amount to be pushed to the remote, and to
2089
        // current rules, while also respecting the settings for the maximum
2090
        // channel size.
2091
        var minFundAmt, fundUpToMaxAmt btcutil.Amount
3✔
2092
        if in.FundMax {
6✔
2093
                // We assume the configured maximum channel size to be the upper
3✔
2094
                // bound of our "maxed" out funding attempt.
3✔
2095
                fundUpToMaxAmt = btcutil.Amount(r.cfg.MaxChanSize)
3✔
2096

3✔
2097
                // Since the standard non-fundmax flow requires the minimum
3✔
2098
                // funding amount to be at least in the amount of the initial
3✔
2099
                // remote balance(push amount) we need to adjust the minimum
3✔
2100
                // funding amount accordingly. We initially assume the minimum
3✔
2101
                // allowed channel size as minimum funding amount.
3✔
2102
                minFundAmt = funding.MinChanFundingSize
3✔
2103

3✔
2104
                // If minFundAmt is less than the initial remote balance we
3✔
2105
                // simply assign the initial remote balance to minFundAmt in
3✔
2106
                // order to fullfil the criterion. Whether or not this so
3✔
2107
                // determined minimum amount is actually available is
3✔
2108
                // ascertained downstream in the lnwallet's reservation
3✔
2109
                // workflow.
3✔
2110
                if remoteInitialBalance >= minFundAmt {
6✔
2111
                        minFundAmt = remoteInitialBalance
3✔
2112
                }
3✔
2113
        }
2114

2115
        minHtlcIn := lnwire.MilliSatoshi(in.MinHtlcMsat)
3✔
2116
        remoteCsvDelay := uint16(in.RemoteCsvDelay)
3✔
2117
        maxValue := lnwire.MilliSatoshi(in.RemoteMaxValueInFlightMsat)
3✔
2118
        maxHtlcs := uint16(in.RemoteMaxHtlcs)
3✔
2119
        remoteChanReserve := btcutil.Amount(in.RemoteChanReserveSat)
3✔
2120

3✔
2121
        globalFeatureSet := r.server.featureMgr.Get(feature.SetNodeAnn)
3✔
2122

3✔
2123
        // Determine if the user provided channel fees
3✔
2124
        // and if so pass them on to the funding workflow.
3✔
2125
        var channelBaseFee, channelFeeRate *uint64
3✔
2126
        if in.UseBaseFee {
6✔
2127
                channelBaseFee = &in.BaseFee
3✔
2128
        }
3✔
2129
        if in.UseFeeRate {
6✔
2130
                channelFeeRate = &in.FeeRate
3✔
2131
        }
3✔
2132

2133
        // Ensure that the remote channel reserve does not exceed 20% of the
2134
        // channel capacity.
2135
        if !in.FundMax && remoteChanReserve >= localFundingAmt/5 {
3✔
2136
                return nil, fmt.Errorf("remote channel reserve must be less " +
×
2137
                        "than the %%20 of the channel capacity")
×
2138
        }
×
2139

2140
        // Ensure that the user doesn't exceed the current soft-limit for
2141
        // channel size. If the funding amount is above the soft-limit, then
2142
        // we'll reject the request.
2143
        // If the FundMax flag is set the local amount is determined downstream
2144
        // in the wallet hence we do not check it here against the maximum
2145
        // funding amount. Only if the localFundingAmt is specified we can check
2146
        // if it exceeds the maximum funding amount.
2147
        wumboEnabled := globalFeatureSet.HasFeature(
3✔
2148
                lnwire.WumboChannelsOptional,
3✔
2149
        )
3✔
2150
        if !in.FundMax && !wumboEnabled && localFundingAmt > MaxFundingAmount {
3✔
2151
                return nil, fmt.Errorf("funding amount is too large, the max "+
×
2152
                        "channel size is: %v", MaxFundingAmount)
×
2153
        }
×
2154

2155
        // Restrict the size of the channel we'll actually open. At a later
2156
        // level, we'll ensure that the output we create, after accounting for
2157
        // fees, does not leave a dust output. In case of the FundMax flow
2158
        // dedicated checks ensure that the lower boundary of the channel size
2159
        // is at least in the amount of MinChanFundingSize or potentially higher
2160
        // if a remote balance is specified.
2161
        if !in.FundMax && localFundingAmt < funding.MinChanFundingSize {
6✔
2162
                return nil, fmt.Errorf("channel is too small, the minimum "+
3✔
2163
                        "channel size is: %v SAT", int64(funding.MinChanFundingSize))
3✔
2164
        }
3✔
2165

2166
        // Prevent users from submitting a max-htlc value that would exceed the
2167
        // protocol maximum.
2168
        if maxHtlcs > input.MaxHTLCNumber/2 {
3✔
2169
                return nil, fmt.Errorf("remote-max-htlcs (%v) cannot be "+
×
2170
                        "greater than %v", maxHtlcs, input.MaxHTLCNumber/2)
×
2171
        }
×
2172

2173
        // Then, we'll extract the minimum number of confirmations that each
2174
        // output we use to fund the channel's funding transaction should
2175
        // satisfy.
2176
        minConfs, err := lnrpc.ExtractMinConfs(in.MinConfs, in.SpendUnconfirmed)
3✔
2177
        if err != nil {
3✔
2178
                return nil, err
×
2179
        }
×
2180

2181
        // TODO(roasbeef): also return channel ID?
2182

2183
        var nodePubKey *btcec.PublicKey
3✔
2184

3✔
2185
        // Parse the remote pubkey the NodePubkey field of the request. If it's
3✔
2186
        // not present, we'll fallback to the deprecated version that parses the
3✔
2187
        // key from a hex string if this is for REST for backwards compatibility.
3✔
2188
        switch {
3✔
2189
        // Parse the raw bytes of the node key into a pubkey object so we can
2190
        // easily manipulate it.
2191
        case len(in.NodePubkey) > 0:
3✔
2192
                nodePubKey, err = btcec.ParsePubKey(in.NodePubkey)
3✔
2193
                if err != nil {
3✔
2194
                        return nil, err
×
2195
                }
×
2196

2197
        // Decode the provided target node's public key, parsing it into a pub
2198
        // key object. For all sync call, byte slices are expected to be encoded
2199
        // as hex strings.
2200
        case isSync:
×
2201
                keyBytes, err := hex.DecodeString(in.NodePubkeyString) // nolint:staticcheck
×
2202
                if err != nil {
×
2203
                        return nil, err
×
2204
                }
×
2205

2206
                nodePubKey, err = btcec.ParsePubKey(keyBytes)
×
2207
                if err != nil {
×
2208
                        return nil, err
×
2209
                }
×
2210

2211
        default:
×
2212
                return nil, fmt.Errorf("NodePubkey is not set")
×
2213
        }
2214

2215
        // Making a channel to ourselves wouldn't be of any use, so we
2216
        // explicitly disallow them.
2217
        if nodePubKey.IsEqual(r.server.identityECDH.PubKey()) {
3✔
2218
                return nil, fmt.Errorf("cannot open channel to self")
×
2219
        }
×
2220

2221
        // NOTE: We also need to do the fee rate calculation for the psbt
2222
        // funding flow because the `batchfund` depends on it.
2223
        targetConf := maybeUseDefaultConf(
3✔
2224
                in.SatPerByte, in.SatPerVbyte, uint32(in.TargetConf),
3✔
2225
        )
3✔
2226

3✔
2227
        // Calculate an appropriate fee rate for this transaction.
3✔
2228
        feeRate, err := lnrpc.CalculateFeeRate(
3✔
2229
                uint64(in.SatPerByte), in.SatPerVbyte,
3✔
2230
                targetConf, r.server.cc.FeeEstimator,
3✔
2231
        )
3✔
2232
        if err != nil {
3✔
2233
                return nil, err
×
2234
        }
×
2235

2236
        rpcsLog.Debugf("[openchannel]: using fee of %v sat/kw for "+
3✔
2237
                "funding tx", int64(feeRate))
3✔
2238

3✔
2239
        script, err := chancloser.ParseUpfrontShutdownAddress(
3✔
2240
                in.CloseAddress, r.cfg.ActiveNetParams.Params,
3✔
2241
        )
3✔
2242
        if err != nil {
3✔
2243
                return nil, fmt.Errorf("error parsing upfront shutdown: %w",
×
2244
                        err)
×
2245
        }
×
2246

2247
        var channelType *lnwire.ChannelType
3✔
2248
        switch in.CommitmentType {
3✔
2249
        case lnrpc.CommitmentType_UNKNOWN_COMMITMENT_TYPE:
3✔
2250
                if in.ZeroConf {
3✔
2251
                        return nil, fmt.Errorf("use anchors for zero-conf")
×
2252
                }
×
2253

2254
        case lnrpc.CommitmentType_LEGACY:
3✔
2255
                channelType = new(lnwire.ChannelType)
3✔
2256
                *channelType = lnwire.ChannelType(*lnwire.NewRawFeatureVector())
3✔
2257

2258
        case lnrpc.CommitmentType_STATIC_REMOTE_KEY:
3✔
2259
                channelType = new(lnwire.ChannelType)
3✔
2260
                *channelType = lnwire.ChannelType(*lnwire.NewRawFeatureVector(
3✔
2261
                        lnwire.StaticRemoteKeyRequired,
3✔
2262
                ))
3✔
2263

2264
        case lnrpc.CommitmentType_ANCHORS:
3✔
2265
                channelType = new(lnwire.ChannelType)
3✔
2266
                fv := lnwire.NewRawFeatureVector(
3✔
2267
                        lnwire.StaticRemoteKeyRequired,
3✔
2268
                        lnwire.AnchorsZeroFeeHtlcTxRequired,
3✔
2269
                )
3✔
2270

3✔
2271
                if in.ZeroConf {
6✔
2272
                        fv.Set(lnwire.ZeroConfRequired)
3✔
2273
                }
3✔
2274

2275
                if in.ScidAlias {
6✔
2276
                        fv.Set(lnwire.ScidAliasRequired)
3✔
2277
                }
3✔
2278

2279
                *channelType = lnwire.ChannelType(*fv)
3✔
2280

2281
        case lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE:
3✔
2282
                channelType = new(lnwire.ChannelType)
3✔
2283
                fv := lnwire.NewRawFeatureVector(
3✔
2284
                        lnwire.StaticRemoteKeyRequired,
3✔
2285
                        lnwire.AnchorsZeroFeeHtlcTxRequired,
3✔
2286
                        lnwire.ScriptEnforcedLeaseRequired,
3✔
2287
                )
3✔
2288

3✔
2289
                if in.ZeroConf {
6✔
2290
                        fv.Set(lnwire.ZeroConfRequired)
3✔
2291
                }
3✔
2292

2293
                if in.ScidAlias {
3✔
2294
                        fv.Set(lnwire.ScidAliasRequired)
×
2295
                }
×
2296

2297
                *channelType = lnwire.ChannelType(*fv)
3✔
2298

2299
        case lnrpc.CommitmentType_SIMPLE_TAPROOT:
3✔
2300
                // If the taproot channel type is being set, then the channel
3✔
2301
                // MUST be private (unadvertised) for now.
3✔
2302
                if !in.Private {
3✔
2303
                        return nil, fmt.Errorf("taproot channels must be " +
×
2304
                                "private")
×
2305
                }
×
2306

2307
                channelType = new(lnwire.ChannelType)
3✔
2308
                fv := lnwire.NewRawFeatureVector(
3✔
2309
                        lnwire.SimpleTaprootChannelsRequiredStaging,
3✔
2310
                )
3✔
2311

3✔
2312
                // TODO(roasbeef): no need for the rest as they're now
3✔
2313
                // implicit?
3✔
2314

3✔
2315
                if in.ZeroConf {
6✔
2316
                        fv.Set(lnwire.ZeroConfRequired)
3✔
2317
                }
3✔
2318

2319
                if in.ScidAlias {
3✔
2320
                        fv.Set(lnwire.ScidAliasRequired)
×
2321
                }
×
2322

2323
                *channelType = lnwire.ChannelType(*fv)
3✔
2324

2325
        case lnrpc.CommitmentType_SIMPLE_TAPROOT_OVERLAY:
×
2326
                // If the taproot overlay channel type is being set, then the
×
2327
                // channel MUST be private.
×
2328
                if !in.Private {
×
2329
                        return nil, fmt.Errorf("taproot overlay channels " +
×
2330
                                "must be private")
×
2331
                }
×
2332

2333
                channelType = new(lnwire.ChannelType)
×
2334
                fv := lnwire.NewRawFeatureVector(
×
2335
                        lnwire.SimpleTaprootOverlayChansRequired,
×
2336
                )
×
2337

×
2338
                if in.ZeroConf {
×
2339
                        fv.Set(lnwire.ZeroConfRequired)
×
2340
                }
×
2341

2342
                if in.ScidAlias {
×
2343
                        fv.Set(lnwire.ScidAliasRequired)
×
2344
                }
×
2345

2346
                *channelType = lnwire.ChannelType(*fv)
×
2347

2348
        default:
×
2349
                return nil, fmt.Errorf("unhandled request channel type %v",
×
2350
                        in.CommitmentType)
×
2351
        }
2352

2353
        // We limit the channel memo to be 500 characters long. This enforces
2354
        // a reasonable upper bound on storage consumption. This also mimics
2355
        // the length limit for the label of a TX.
2356
        const maxMemoLength = 500
3✔
2357
        if len(in.Memo) > maxMemoLength {
6✔
2358
                return nil, fmt.Errorf("provided memo (%s) is of length %d, "+
3✔
2359
                        "exceeds %d", in.Memo, len(in.Memo), maxMemoLength)
3✔
2360
        }
3✔
2361

2362
        // Check, if manually selected outpoints are present to fund a channel.
2363
        var outpoints []wire.OutPoint
3✔
2364
        if len(in.Outpoints) > 0 {
6✔
2365
                outpoints, err = toWireOutpoints(in.Outpoints)
3✔
2366
                if err != nil {
3✔
2367
                        return nil, fmt.Errorf("can't create outpoints %w", err)
×
2368
                }
×
2369
        }
2370

2371
        // Instruct the server to trigger the necessary events to attempt to
2372
        // open a new channel. A stream is returned in place, this stream will
2373
        // be used to consume updates of the state of the pending channel.
2374
        return &funding.InitFundingMsg{
3✔
2375
                TargetPubkey:    nodePubKey,
3✔
2376
                ChainHash:       *r.cfg.ActiveNetParams.GenesisHash,
3✔
2377
                LocalFundingAmt: localFundingAmt,
3✔
2378
                BaseFee:         channelBaseFee,
3✔
2379
                FeeRate:         channelFeeRate,
3✔
2380
                PushAmt: lnwire.NewMSatFromSatoshis(
3✔
2381
                        remoteInitialBalance,
3✔
2382
                ),
3✔
2383
                MinHtlcIn:         minHtlcIn,
3✔
2384
                FundingFeePerKw:   feeRate,
3✔
2385
                Private:           in.Private,
3✔
2386
                RemoteCsvDelay:    remoteCsvDelay,
3✔
2387
                RemoteChanReserve: remoteChanReserve,
3✔
2388
                MinConfs:          minConfs,
3✔
2389
                ShutdownScript:    script,
3✔
2390
                MaxValueInFlight:  maxValue,
3✔
2391
                MaxHtlcs:          maxHtlcs,
3✔
2392
                MaxLocalCsv:       uint16(in.MaxLocalCsv),
3✔
2393
                ChannelType:       channelType,
3✔
2394
                FundUpToMaxAmt:    fundUpToMaxAmt,
3✔
2395
                MinFundAmt:        minFundAmt,
3✔
2396
                Memo:              []byte(in.Memo),
3✔
2397
                Outpoints:         outpoints,
3✔
2398
        }, nil
3✔
2399
}
2400

2401
// toWireOutpoints converts a list of outpoints from the rpc format to the wire
2402
// format.
2403
func toWireOutpoints(outpoints []*lnrpc.OutPoint) ([]wire.OutPoint, error) {
3✔
2404
        var wireOutpoints []wire.OutPoint
3✔
2405
        for _, outpoint := range outpoints {
6✔
2406
                hash, err := chainhash.NewHashFromStr(outpoint.TxidStr)
3✔
2407
                if err != nil {
3✔
2408
                        return nil, fmt.Errorf("cannot create chainhash")
×
2409
                }
×
2410

2411
                wireOutpoint := wire.NewOutPoint(
3✔
2412
                        hash, outpoint.OutputIndex,
3✔
2413
                )
3✔
2414
                wireOutpoints = append(wireOutpoints, *wireOutpoint)
3✔
2415
        }
2416

2417
        return wireOutpoints, nil
3✔
2418
}
2419

2420
// OpenChannel attempts to open a singly funded channel specified in the
2421
// request to a remote peer.
2422
func (r *rpcServer) OpenChannel(in *lnrpc.OpenChannelRequest,
2423
        updateStream lnrpc.Lightning_OpenChannelServer) error {
3✔
2424

3✔
2425
        if err := r.canOpenChannel(); err != nil {
3✔
2426
                return err
×
2427
        }
×
2428

2429
        req, err := r.parseOpenChannelReq(in, false)
3✔
2430
        if err != nil {
6✔
2431
                return err
3✔
2432
        }
3✔
2433

2434
        // If the user has provided a shim, then we'll now augment the based
2435
        // open channel request with this additional logic.
2436
        if in.FundingShim != nil {
6✔
2437
                switch {
3✔
2438
                // If we have a chan point shim, then this means the funding
2439
                // transaction was crafted externally. In this case we only
2440
                // need to hand a channel point down into the wallet.
2441
                case in.FundingShim.GetChanPointShim() != nil:
3✔
2442
                        chanPointShim := in.FundingShim.GetChanPointShim()
3✔
2443

3✔
2444
                        // Map the channel point shim into a new
3✔
2445
                        // chanfunding.CannedAssembler that the wallet will use
3✔
2446
                        // to obtain the channel point details.
3✔
2447
                        copy(req.PendingChanID[:], chanPointShim.PendingChanId)
3✔
2448
                        req.ChanFunder, err = newFundingShimAssembler(
3✔
2449
                                chanPointShim, true, r.server.cc.KeyRing,
3✔
2450
                        )
3✔
2451
                        if err != nil {
3✔
2452
                                return err
×
2453
                        }
×
2454

2455
                // If we have a PSBT shim, then this means the funding
2456
                // transaction will be crafted outside of the wallet, once the
2457
                // funding multisig output script is known. We'll create an
2458
                // intent that will supervise the multi-step process.
2459
                case in.FundingShim.GetPsbtShim() != nil:
3✔
2460
                        psbtShim := in.FundingShim.GetPsbtShim()
3✔
2461

3✔
2462
                        // Instruct the wallet to use the new
3✔
2463
                        // chanfunding.PsbtAssembler to construct the funding
3✔
2464
                        // transaction.
3✔
2465
                        copy(req.PendingChanID[:], psbtShim.PendingChanId)
3✔
2466

3✔
2467
                        // NOTE: For the PSBT case we do also allow unconfirmed
3✔
2468
                        // utxos to fund the psbt transaction because we make
3✔
2469
                        // sure we only use stable utxos.
3✔
2470
                        req.ChanFunder, err = newPsbtAssembler(
3✔
2471
                                in, psbtShim,
3✔
2472
                                &r.server.cc.Wallet.Cfg.NetParams,
3✔
2473
                        )
3✔
2474
                        if err != nil {
3✔
2475
                                return err
×
2476
                        }
×
2477
                }
2478
        }
2479

2480
        updateChan, errChan := r.server.OpenChannel(req)
3✔
2481

3✔
2482
        var outpoint wire.OutPoint
3✔
2483
out:
3✔
2484
        for {
6✔
2485
                select {
3✔
2486
                case err := <-errChan:
3✔
2487
                        rpcsLog.Errorf("unable to open channel to NodeKey(%x): %v",
3✔
2488
                                req.TargetPubkey.SerializeCompressed(), err)
3✔
2489
                        return err
3✔
2490
                case fundingUpdate := <-updateChan:
3✔
2491
                        rpcsLog.Tracef("[openchannel] sending update: %v",
3✔
2492
                                fundingUpdate)
3✔
2493
                        if err := updateStream.Send(fundingUpdate); err != nil {
3✔
2494
                                return err
×
2495
                        }
×
2496

2497
                        // If a final channel open update is being sent, then
2498
                        // we can break out of our recv loop as we no longer
2499
                        // need to process any further updates.
2500
                        update, ok := fundingUpdate.Update.(*lnrpc.OpenStatusUpdate_ChanOpen)
3✔
2501
                        if ok {
6✔
2502
                                chanPoint := update.ChanOpen.ChannelPoint
3✔
2503
                                txid, err := lnrpc.GetChanPointFundingTxid(chanPoint)
3✔
2504
                                if err != nil {
3✔
2505
                                        return err
×
2506
                                }
×
2507
                                outpoint = wire.OutPoint{
3✔
2508
                                        Hash:  *txid,
3✔
2509
                                        Index: chanPoint.OutputIndex,
3✔
2510
                                }
3✔
2511

3✔
2512
                                break out
3✔
2513
                        }
2514
                case <-r.quit:
3✔
2515
                        return nil
3✔
2516
                }
2517
        }
2518

2519
        rpcsLog.Tracef("[openchannel] success NodeKey(%x), ChannelPoint(%v)",
3✔
2520
                req.TargetPubkey.SerializeCompressed(), outpoint)
3✔
2521
        return nil
3✔
2522
}
2523

2524
// OpenChannelSync is a synchronous version of the OpenChannel RPC call. This
2525
// call is meant to be consumed by clients to the REST proxy. As with all other
2526
// sync calls, all byte slices are instead to be populated as hex encoded
2527
// strings.
2528
func (r *rpcServer) OpenChannelSync(ctx context.Context,
2529
        in *lnrpc.OpenChannelRequest) (*lnrpc.ChannelPoint, error) {
×
2530

×
2531
        if err := r.canOpenChannel(); err != nil {
×
2532
                return nil, err
×
2533
        }
×
2534

2535
        req, err := r.parseOpenChannelReq(in, true)
×
2536
        if err != nil {
×
2537
                return nil, err
×
2538
        }
×
2539

2540
        updateChan, errChan := r.server.OpenChannel(req)
×
2541
        select {
×
2542
        // If an error occurs them immediately return the error to the client.
2543
        case err := <-errChan:
×
2544
                rpcsLog.Errorf("unable to open channel to NodeKey(%x): %v",
×
2545
                        req.TargetPubkey.SerializeCompressed(), err)
×
2546
                return nil, err
×
2547

2548
        // Otherwise, wait for the first channel update. The first update sent
2549
        // is when the funding transaction is broadcast to the network.
2550
        case fundingUpdate := <-updateChan:
×
2551
                rpcsLog.Tracef("[openchannel] sending update: %v",
×
2552
                        fundingUpdate)
×
2553

×
2554
                // Parse out the txid of the pending funding transaction. The
×
2555
                // sync client can use this to poll against the list of
×
2556
                // PendingChannels.
×
2557
                openUpdate := fundingUpdate.Update.(*lnrpc.OpenStatusUpdate_ChanPending)
×
2558
                chanUpdate := openUpdate.ChanPending
×
2559

×
2560
                return &lnrpc.ChannelPoint{
×
2561
                        FundingTxid: &lnrpc.ChannelPoint_FundingTxidBytes{
×
2562
                                FundingTxidBytes: chanUpdate.Txid,
×
2563
                        },
×
2564
                        OutputIndex: chanUpdate.OutputIndex,
×
2565
                }, nil
×
2566
        case <-r.quit:
×
2567
                return nil, nil
×
2568
        }
2569
}
2570

2571
// BatchOpenChannel attempts to open multiple single-funded channels in a
2572
// single transaction in an atomic way. This means either all channel open
2573
// requests succeed at once or all attempts are aborted if any of them fail.
2574
// This is the safer variant of using PSBTs to manually fund a batch of
2575
// channels through the OpenChannel RPC.
2576
func (r *rpcServer) BatchOpenChannel(ctx context.Context,
2577
        in *lnrpc.BatchOpenChannelRequest) (*lnrpc.BatchOpenChannelResponse,
2578
        error) {
3✔
2579

3✔
2580
        if err := r.canOpenChannel(); err != nil {
3✔
2581
                return nil, err
×
2582
        }
×
2583

2584
        // We need the wallet kit server to do the heavy lifting on the PSBT
2585
        // part. If we didn't rely on re-using the wallet kit server's logic we
2586
        // would need to re-implement everything here. Since we deliver lnd with
2587
        // the wallet kit server enabled by default we can assume it's okay to
2588
        // make this functionality dependent on that server being active.
2589
        var walletKitServer walletrpc.WalletKitServer
3✔
2590
        for _, subServer := range r.subServers {
6✔
2591
                if subServer.Name() == walletrpc.SubServerName {
6✔
2592
                        walletKitServer = subServer.(walletrpc.WalletKitServer)
3✔
2593
                }
3✔
2594
        }
2595
        if walletKitServer == nil {
3✔
2596
                return nil, fmt.Errorf("batch channel open is only possible " +
×
2597
                        "if walletrpc subserver is active")
×
2598
        }
×
2599

2600
        rpcsLog.Debugf("[batchopenchannel] request to open batch of %d "+
3✔
2601
                "channels", len(in.Channels))
3✔
2602

3✔
2603
        // Make sure there is at least one channel to open. We could say we want
3✔
2604
        // at least two channels for a batch. But maybe it's nice if developers
3✔
2605
        // can use the same API for a single channel as well as a batch of
3✔
2606
        // channels.
3✔
2607
        if len(in.Channels) == 0 {
3✔
2608
                return nil, fmt.Errorf("specify at least one channel")
×
2609
        }
×
2610

2611
        // In case we remove a pending channel from the database, we need to set
2612
        // a close height, so we'll just use the current best known height.
2613
        _, bestHeight, err := r.server.cc.ChainIO.GetBestBlock()
3✔
2614
        if err != nil {
3✔
2615
                return nil, fmt.Errorf("error fetching best block: %w", err)
×
2616
        }
×
2617

2618
        // So far everything looks good and we can now start the heavy lifting
2619
        // that's done in the funding package.
2620
        requestParser := func(req *lnrpc.OpenChannelRequest) (
3✔
2621
                *funding.InitFundingMsg, error) {
6✔
2622

3✔
2623
                return r.parseOpenChannelReq(req, false)
3✔
2624
        }
3✔
2625
        channelAbandoner := func(point *wire.OutPoint) error {
3✔
2626
                return r.abandonChan(point, uint32(bestHeight))
×
2627
        }
×
2628
        batcher := funding.NewBatcher(&funding.BatchConfig{
3✔
2629
                RequestParser:    requestParser,
3✔
2630
                ChannelAbandoner: channelAbandoner,
3✔
2631
                ChannelOpener:    r.server.OpenChannel,
3✔
2632
                WalletKitServer:  walletKitServer,
3✔
2633
                Wallet:           r.server.cc.Wallet,
3✔
2634
                NetParams:        &r.server.cc.Wallet.Cfg.NetParams,
3✔
2635
                Quit:             r.quit,
3✔
2636
        })
3✔
2637
        rpcPoints, err := batcher.BatchFund(ctx, in)
3✔
2638
        if err != nil {
6✔
2639
                return nil, fmt.Errorf("batch funding failed: %w", err)
3✔
2640
        }
3✔
2641

2642
        // Now all that's left to do is send back the response with the channel
2643
        // points we created.
2644
        return &lnrpc.BatchOpenChannelResponse{
3✔
2645
                PendingChannels: rpcPoints,
3✔
2646
        }, nil
3✔
2647
}
2648

2649
// CloseChannel attempts to close an active channel identified by its channel
2650
// point. The actions of this method can additionally be augmented to attempt
2651
// a force close after a timeout period in the case of an inactive peer.
2652
func (r *rpcServer) CloseChannel(in *lnrpc.CloseChannelRequest,
2653
        updateStream lnrpc.Lightning_CloseChannelServer) error {
3✔
2654

3✔
2655
        if !r.server.Started() {
3✔
2656
                return ErrServerNotActive
×
2657
        }
×
2658

2659
        // If the user didn't specify a channel point, then we'll reject this
2660
        // request all together.
2661
        if in.GetChannelPoint() == nil {
3✔
2662
                return fmt.Errorf("must specify channel point in close channel")
×
2663
        }
×
2664

2665
        // If force closing a channel, the fee set in the commitment transaction
2666
        // is used.
2667
        if in.Force && (in.SatPerByte != 0 || in.SatPerVbyte != 0 || // nolint:staticcheck
3✔
2668
                in.TargetConf != 0) {
3✔
2669

×
2670
                return fmt.Errorf("force closing a channel uses a pre-defined fee")
×
2671
        }
×
2672

2673
        force := in.Force
3✔
2674
        index := in.ChannelPoint.OutputIndex
3✔
2675
        txid, err := lnrpc.GetChanPointFundingTxid(in.GetChannelPoint())
3✔
2676
        if err != nil {
3✔
2677
                rpcsLog.Errorf("[closechannel] unable to get funding txid: %v", err)
×
2678
                return err
×
2679
        }
×
2680
        chanPoint := wire.NewOutPoint(txid, index)
3✔
2681

3✔
2682
        rpcsLog.Tracef("[closechannel] request for ChannelPoint(%v), force=%v",
3✔
2683
                chanPoint, force)
3✔
2684

3✔
2685
        var (
3✔
2686
                updateChan chan interface{}
3✔
2687
                errChan    chan error
3✔
2688
        )
3✔
2689

3✔
2690
        // TODO(roasbeef): if force and peer online then don't force?
3✔
2691

3✔
2692
        // First, we'll fetch the channel as is, as we'll need to examine it
3✔
2693
        // regardless of if this is a force close or not.
3✔
2694
        channel, err := r.server.chanStateDB.FetchChannel(*chanPoint)
3✔
2695
        if err != nil {
3✔
2696
                return err
×
2697
        }
×
2698

2699
        // We can't coop or force close restored channels or channels that have
2700
        // experienced local data loss. Normally we would detect this in the
2701
        // channel arbitrator if the channel has the status
2702
        // ChanStatusLocalDataLoss after connecting to its peer. But if no
2703
        // connection can be established, the channel arbitrator doesn't know it
2704
        // can't be force closed yet.
2705
        if channel.HasChanStatus(channeldb.ChanStatusRestored) ||
3✔
2706
                channel.HasChanStatus(channeldb.ChanStatusLocalDataLoss) {
6✔
2707

3✔
2708
                return fmt.Errorf("cannot close channel with state: %v",
3✔
2709
                        channel.ChanStatus())
3✔
2710
        }
3✔
2711

2712
        // Retrieve the best height of the chain, which we'll use to complete
2713
        // either closing flow.
2714
        _, bestHeight, err := r.server.cc.ChainIO.GetBestBlock()
3✔
2715
        if err != nil {
3✔
2716
                return err
×
2717
        }
×
2718

2719
        // Retrieve the number of active HTLCs on the channel.
2720
        activeHtlcs := channel.ActiveHtlcs()
3✔
2721

3✔
2722
        // If a force closure was requested, then we'll handle all the details
3✔
2723
        // around the creation and broadcast of the unilateral closure
3✔
2724
        // transaction here rather than going to the switch as we don't require
3✔
2725
        // interaction from the peer.
3✔
2726
        if force {
6✔
2727
                // As we're force closing this channel, as a precaution, we'll
3✔
2728
                // ensure that the switch doesn't continue to see this channel
3✔
2729
                // as eligible for forwarding HTLC's. If the peer is online,
3✔
2730
                // then we'll also purge all of its indexes.
3✔
2731
                remotePub := channel.IdentityPub
3✔
2732
                if peer, err := r.server.FindPeer(remotePub); err == nil {
6✔
2733
                        // TODO(roasbeef): actually get the active channel
3✔
2734
                        // instead too?
3✔
2735
                        //  * so only need to grab from database
3✔
2736
                        peer.WipeChannel(&channel.FundingOutpoint)
3✔
2737
                } else {
6✔
2738
                        chanID := lnwire.NewChanIDFromOutPoint(
3✔
2739
                                channel.FundingOutpoint,
3✔
2740
                        )
3✔
2741
                        r.server.htlcSwitch.RemoveLink(chanID)
3✔
2742
                }
3✔
2743

2744
                // With the necessary indexes cleaned up, we'll now force close
2745
                // the channel.
2746
                chainArbitrator := r.server.chainArb
3✔
2747
                closingTx, err := chainArbitrator.ForceCloseContract(
3✔
2748
                        *chanPoint,
3✔
2749
                )
3✔
2750
                if err != nil {
3✔
2751
                        rpcsLog.Errorf("unable to force close transaction: %v", err)
×
2752
                        return err
×
2753
                }
×
2754

2755
                // Safety check which should never happen.
2756
                //
2757
                // TODO(ziggie): remove pointer as return value from
2758
                // ForceCloseContract.
2759
                if closingTx == nil {
3✔
2760
                        return fmt.Errorf("force close transaction is nil")
×
2761
                }
×
2762

2763
                closingTxid := closingTx.TxHash()
3✔
2764

3✔
2765
                // With the transaction broadcast, we send our first update to
3✔
2766
                // the client.
3✔
2767
                updateChan = make(chan interface{}, 2)
3✔
2768
                updateChan <- &peer.PendingUpdate{
3✔
2769
                        Txid: closingTxid[:],
3✔
2770
                }
3✔
2771

3✔
2772
                errChan = make(chan error, 1)
3✔
2773
                notifier := r.server.cc.ChainNotifier
3✔
2774
                go peer.WaitForChanToClose(
3✔
2775
                        uint32(bestHeight), notifier, errChan, chanPoint,
3✔
2776
                        &closingTxid, closingTx.TxOut[0].PkScript, func() {
6✔
2777
                                // Respond to the local subsystem which
3✔
2778
                                // requested the channel closure.
3✔
2779
                                updateChan <- &peer.ChannelCloseUpdate{
3✔
2780
                                        ClosingTxid: closingTxid[:],
3✔
2781
                                        Success:     true,
3✔
2782
                                        // Force closure transactions don't have
3✔
2783
                                        // additional local/remote outputs.
3✔
2784
                                }
3✔
2785
                        },
3✔
2786
                )
2787
        } else {
3✔
2788
                // If this is a frozen channel, then we only allow the co-op
3✔
2789
                // close to proceed if we were the responder to this channel if
3✔
2790
                // the absolute thaw height has not been met.
3✔
2791
                if channel.IsInitiator {
6✔
2792
                        absoluteThawHeight, err := channel.AbsoluteThawHeight()
3✔
2793
                        if err != nil {
3✔
2794
                                return err
×
2795
                        }
×
2796
                        if uint32(bestHeight) < absoluteThawHeight {
6✔
2797
                                return fmt.Errorf("cannot co-op close frozen "+
3✔
2798
                                        "channel as initiator until height=%v, "+
3✔
2799
                                        "(current_height=%v)",
3✔
2800
                                        absoluteThawHeight, bestHeight)
3✔
2801
                        }
3✔
2802
                }
2803

2804
                var (
3✔
2805
                        chanInSwitch     = true
3✔
2806
                        chanHasRbfCloser = r.server.ChanHasRbfCoopCloser(
3✔
2807
                                channel.IdentityPub, *chanPoint,
3✔
2808
                        )
3✔
2809
                )
3✔
2810

3✔
2811
                // If the link is not known by the switch, we cannot gracefully close
3✔
2812
                // the channel.
3✔
2813
                channelID := lnwire.NewChanIDFromOutPoint(*chanPoint)
3✔
2814

3✔
2815
                if _, err := r.server.htlcSwitch.GetLink(channelID); err != nil {
6✔
2816
                        chanInSwitch = false
3✔
2817

3✔
2818
                        // The channel isn't in the switch, but if there's an
3✔
2819
                        // active chan closer for the channel, and it's of the
3✔
2820
                        // RBF variant, then we can actually bypass the switch.
3✔
2821
                        // Otherwise, we'll return an error.
3✔
2822
                        if !chanHasRbfCloser {
3✔
2823
                                rpcsLog.Debugf("Trying to non-force close "+
×
2824
                                        "offline channel with chan_point=%v",
×
2825
                                        chanPoint)
×
2826

×
2827
                                return fmt.Errorf("unable to gracefully close "+
×
2828
                                        "channel while peer is offline (try "+
×
2829
                                        "force closing it instead): %v", err)
×
2830
                        }
×
2831
                }
2832

2833
                // Keep the old behavior prior to 0.18.0 - when the user
2834
                // doesn't set fee rate or conf target, the default conf target
2835
                // of 6 is used.
2836
                targetConf := maybeUseDefaultConf(
3✔
2837
                        in.SatPerByte, in.SatPerVbyte, uint32(in.TargetConf),
3✔
2838
                )
3✔
2839

3✔
2840
                // Based on the passed fee related parameters, we'll determine
3✔
2841
                // an appropriate fee rate for the cooperative closure
3✔
2842
                // transaction.
3✔
2843
                feeRate, err := lnrpc.CalculateFeeRate(
3✔
2844
                        uint64(in.SatPerByte), in.SatPerVbyte, // nolint:staticcheck
3✔
2845
                        targetConf, r.server.cc.FeeEstimator,
3✔
2846
                )
3✔
2847
                if err != nil {
3✔
2848
                        return err
×
2849
                }
×
2850

2851
                rpcsLog.Debugf("Target sat/kw for closing transaction: %v",
3✔
2852
                        int64(feeRate))
3✔
2853

3✔
2854
                // If the user hasn't specified NoWait, then before we attempt
3✔
2855
                // to close the channel we ensure there are no active HTLCs on
3✔
2856
                // the link.
3✔
2857
                if !in.NoWait && len(activeHtlcs) != 0 {
3✔
2858
                        return fmt.Errorf("cannot coop close channel with "+
×
2859
                                "active htlcs (number of active htlcs: %d), "+
×
2860
                                "bypass this check and initiate the coop "+
×
2861
                                "close by setting no_wait=true",
×
2862
                                len(activeHtlcs))
×
2863
                }
×
2864

2865
                // Otherwise, the caller has requested a regular interactive
2866
                // cooperative channel closure. So we'll forward the request to
2867
                // the htlc switch which will handle the negotiation and
2868
                // broadcast details.
2869

2870
                var deliveryScript lnwire.DeliveryAddress
3✔
2871

3✔
2872
                // If a delivery address to close out to was specified, decode it.
3✔
2873
                if len(in.DeliveryAddress) > 0 {
6✔
2874
                        // Decode the address provided.
3✔
2875
                        addr, err := btcutil.DecodeAddress(
3✔
2876
                                in.DeliveryAddress, r.cfg.ActiveNetParams.Params,
3✔
2877
                        )
3✔
2878
                        if err != nil {
3✔
2879
                                return fmt.Errorf("invalid delivery address: "+
×
2880
                                        "%v", err)
×
2881
                        }
×
2882

2883
                        if !addr.IsForNet(r.cfg.ActiveNetParams.Params) {
3✔
2884
                                return fmt.Errorf("delivery address is not "+
×
2885
                                        "for %s",
×
2886
                                        r.cfg.ActiveNetParams.Params.Name)
×
2887
                        }
×
2888

2889
                        // Create a script to pay out to the address provided.
2890
                        deliveryScript, err = txscript.PayToAddrScript(addr)
3✔
2891
                        if err != nil {
3✔
2892
                                return err
×
2893
                        }
×
2894
                }
2895

2896
                maxFee := chainfee.SatPerKVByte(
3✔
2897
                        in.MaxFeePerVbyte * 1000,
3✔
2898
                ).FeePerKWeight()
3✔
2899

3✔
2900
                // In case the max fee was specified, we check if it's less than
3✔
2901
                // the initial fee rate and abort if it is.
3✔
2902
                if maxFee != 0 && maxFee < feeRate {
6✔
2903
                        return fmt.Errorf("max_fee_per_vbyte (%v) is less "+
3✔
2904
                                "than the required fee rate (%v)", maxFee,
3✔
2905
                                feeRate)
3✔
2906
                }
3✔
2907

2908
                if chanHasRbfCloser && !chanInSwitch {
6✔
2909
                        rpcsLog.Infof("Bypassing Switch to do fee bump "+
3✔
2910
                                "for ChannelPoint(%v)", chanPoint)
3✔
2911

3✔
2912
                        closeUpdates, err := r.server.AttemptRBFCloseUpdate(
3✔
2913
                                updateStream.Context(), *chanPoint, feeRate,
3✔
2914
                                deliveryScript,
3✔
2915
                        )
3✔
2916
                        if err != nil {
3✔
2917
                                return fmt.Errorf("unable to do RBF close "+
×
2918
                                        "update: %w", err)
×
2919
                        }
×
2920

2921
                        updateChan = closeUpdates.UpdateChan
3✔
2922
                        errChan = closeUpdates.ErrChan
3✔
2923
                } else {
3✔
2924
                        maxFee := chainfee.SatPerKVByte(
3✔
2925
                                in.MaxFeePerVbyte * 1000,
3✔
2926
                        ).FeePerKWeight()
3✔
2927
                        updateChan, errChan = r.server.htlcSwitch.CloseLink(
3✔
2928
                                updateStream.Context(), chanPoint,
3✔
2929
                                contractcourt.CloseRegular, feeRate, maxFee,
3✔
2930
                                deliveryScript,
3✔
2931
                        )
3✔
2932
                }
3✔
2933
        }
2934

2935
        // If the user doesn't want to wait for the txid to come back then we
2936
        // will send an empty update to kick off the stream. This is also used
2937
        // when active htlcs are still on the channel to give the client
2938
        // immediate feedback.
2939
        if in.NoWait {
6✔
2940
                rpcsLog.Trace("[closechannel] sending instant update")
3✔
2941
                if err := updateStream.Send(
3✔
2942
                        //nolint:ll
3✔
2943
                        &lnrpc.CloseStatusUpdate{
3✔
2944
                                Update: &lnrpc.CloseStatusUpdate_CloseInstant{
3✔
2945
                                        CloseInstant: &lnrpc.InstantUpdate{
3✔
2946
                                                NumPendingHtlcs: int32(len(activeHtlcs)),
3✔
2947
                                        },
3✔
2948
                                },
3✔
2949
                        },
3✔
2950
                ); err != nil {
3✔
2951
                        return err
×
2952
                }
×
2953
        }
2954

2955
out:
3✔
2956
        for {
6✔
2957
                select {
3✔
2958
                case err := <-errChan:
3✔
2959
                        rpcsLog.Errorf("[closechannel] unable to close "+
3✔
2960
                                "ChannelPoint(%v): %v", chanPoint, err)
3✔
2961

3✔
2962
                        return err
3✔
2963

2964
                case closingUpdate := <-updateChan:
3✔
2965
                        rpcClosingUpdate, err := createRPCCloseUpdate(
3✔
2966
                                closingUpdate,
3✔
2967
                        )
3✔
2968
                        if err != nil {
3✔
2969
                                return err
×
2970
                        }
×
2971

2972
                        err = fn.MapOptionZ(
3✔
2973
                                r.server.implCfg.AuxDataParser,
3✔
2974
                                func(parser AuxDataParser) error {
3✔
2975
                                        return parser.InlineParseCustomData(
×
2976
                                                rpcClosingUpdate,
×
2977
                                        )
×
2978
                                },
×
2979
                        )
2980
                        if err != nil {
3✔
2981
                                return fmt.Errorf("error parsing custom data: "+
×
2982
                                        "%w", err)
×
2983
                        }
×
2984

2985
                        rpcsLog.Tracef("[closechannel] sending update: %v",
3✔
2986
                                rpcClosingUpdate)
3✔
2987

3✔
2988
                        if err := updateStream.Send(rpcClosingUpdate); err != nil {
3✔
2989
                                return err
×
2990
                        }
×
2991

2992
                        // If a final channel closing updates is being sent,
2993
                        // then we can break out of our dispatch loop as we no
2994
                        // longer need to process any further updates.
2995
                        switch closeUpdate := closingUpdate.(type) {
3✔
2996
                        case *peer.ChannelCloseUpdate:
3✔
2997
                                h, _ := chainhash.NewHash(closeUpdate.ClosingTxid)
3✔
2998
                                rpcsLog.Infof("[closechannel] close completed: "+
3✔
2999
                                        "txid(%v)", h)
3✔
3000

3✔
3001
                                break out
3✔
3002
                        }
3003

3004
                case <-r.quit:
3✔
3005
                        return nil
3✔
3006
                }
3007
        }
3008

3009
        return nil
3✔
3010
}
3011

3012
func createRPCCloseUpdate(
3013
        update interface{}) (*lnrpc.CloseStatusUpdate, error) {
3✔
3014

3✔
3015
        switch u := update.(type) {
3✔
3016
        case *peer.ChannelCloseUpdate:
3✔
3017
                ccu := &lnrpc.ChannelCloseUpdate{
3✔
3018
                        ClosingTxid: u.ClosingTxid,
3✔
3019
                        Success:     u.Success,
3✔
3020
                }
3✔
3021

3✔
3022
                err := fn.MapOptionZ(
3✔
3023
                        u.LocalCloseOutput,
3✔
3024
                        func(closeOut chancloser.CloseOutput) error {
6✔
3025
                                cr, err := closeOut.ShutdownRecords.Serialize()
3✔
3026
                                if err != nil {
3✔
3027
                                        return fmt.Errorf("error serializing "+
×
3028
                                                "local close out custom "+
×
3029
                                                "records: %w", err)
×
3030
                                }
×
3031

3032
                                rpcCloseOut := &lnrpc.CloseOutput{
3✔
3033
                                        AmountSat:         int64(closeOut.Amt),
3✔
3034
                                        PkScript:          closeOut.PkScript,
3✔
3035
                                        IsLocal:           true,
3✔
3036
                                        CustomChannelData: cr,
3✔
3037
                                }
3✔
3038
                                ccu.LocalCloseOutput = rpcCloseOut
3✔
3039

3✔
3040
                                return nil
3✔
3041
                        },
3042
                )
3043
                if err != nil {
3✔
3044
                        return nil, err
×
3045
                }
×
3046

3047
                err = fn.MapOptionZ(
3✔
3048
                        u.RemoteCloseOutput,
3✔
3049
                        func(closeOut chancloser.CloseOutput) error {
6✔
3050
                                cr, err := closeOut.ShutdownRecords.Serialize()
3✔
3051
                                if err != nil {
3✔
3052
                                        return fmt.Errorf("error serializing "+
×
3053
                                                "remote close out custom "+
×
3054
                                                "records: %w", err)
×
3055
                                }
×
3056

3057
                                rpcCloseOut := &lnrpc.CloseOutput{
3✔
3058
                                        AmountSat:         int64(closeOut.Amt),
3✔
3059
                                        PkScript:          closeOut.PkScript,
3✔
3060
                                        CustomChannelData: cr,
3✔
3061
                                }
3✔
3062
                                ccu.RemoteCloseOutput = rpcCloseOut
3✔
3063

3✔
3064
                                return nil
3✔
3065
                        },
3066
                )
3067
                if err != nil {
3✔
3068
                        return nil, err
×
3069
                }
×
3070

3071
                u.AuxOutputs.WhenSome(func(outs chancloser.AuxCloseOutputs) {
3✔
3072
                        for _, out := range outs.ExtraCloseOutputs {
×
3073
                                ccu.AdditionalOutputs = append(
×
3074
                                        ccu.AdditionalOutputs,
×
3075
                                        &lnrpc.CloseOutput{
×
3076
                                                AmountSat: out.Value,
×
3077
                                                PkScript:  out.PkScript,
×
3078
                                                IsLocal:   out.IsLocal,
×
3079
                                        },
×
3080
                                )
×
3081
                        }
×
3082
                })
3083

3084
                return &lnrpc.CloseStatusUpdate{
3✔
3085
                        Update: &lnrpc.CloseStatusUpdate_ChanClose{
3✔
3086
                                ChanClose: ccu,
3✔
3087
                        },
3✔
3088
                }, nil
3✔
3089

3090
        case *peer.PendingUpdate:
3✔
3091
                upd := &lnrpc.PendingUpdate{
3✔
3092
                        Txid:        u.Txid,
3✔
3093
                        OutputIndex: u.OutputIndex,
3✔
3094
                }
3✔
3095

3✔
3096
                // Potentially set the optional fields that are only set for
3✔
3097
                // the new RBF close flow.
3✔
3098
                u.IsLocalCloseTx.WhenSome(func(isLocal bool) {
6✔
3099
                        upd.LocalCloseTx = isLocal
3✔
3100
                })
3✔
3101
                u.FeePerVbyte.WhenSome(func(feeRate chainfee.SatPerVByte) {
6✔
3102
                        upd.FeePerVbyte = int64(feeRate)
3✔
3103
                })
3✔
3104

3105
                return &lnrpc.CloseStatusUpdate{
3✔
3106
                        Update: &lnrpc.CloseStatusUpdate_ClosePending{
3✔
3107
                                ClosePending: upd,
3✔
3108
                        },
3✔
3109
                }, nil
3✔
3110
        }
3111

3112
        return nil, errors.New("unknown close status update")
×
3113
}
3114

3115
// abandonChanFromGraph attempts to remove a channel from the channel graph. If
3116
// we can't find the chanID in the graph, then we assume it has already been
3117
// removed, and will return a nop.
3118
func abandonChanFromGraph(chanGraph *graphdb.ChannelGraph,
3119
        chanPoint *wire.OutPoint) error {
3✔
3120

3✔
3121
        // First, we'll obtain the channel ID. If we can't locate this, then
3✔
3122
        // it's the case that the channel may have already been removed from
3✔
3123
        // the graph, so we'll return a nil error.
3✔
3124
        chanID, err := chanGraph.ChannelID(chanPoint)
3✔
3125
        switch {
3✔
3126
        case errors.Is(err, graphdb.ErrEdgeNotFound):
3✔
3127
                return nil
3✔
3128
        case err != nil:
×
3129
                return err
×
3130
        }
3131

3132
        // If the channel ID is still in the graph, then that means the channel
3133
        // is still open, so we'll now move to purge it from the graph.
3134
        return chanGraph.DeleteChannelEdges(false, true, chanID)
3✔
3135
}
3136

3137
// abandonChan removes a channel from the database, graph and contract court.
3138
func (r *rpcServer) abandonChan(chanPoint *wire.OutPoint,
3139
        bestHeight uint32) error {
3✔
3140

3✔
3141
        // Before we remove the channel we cancel the rebroadcasting of the
3✔
3142
        // transaction. If this transaction does not exist in the rebroadcast
3✔
3143
        // queue anymore it is a noop.
3✔
3144
        txid, err := chainhash.NewHash(chanPoint.Hash[:])
3✔
3145
        if err != nil {
3✔
3146
                return err
×
3147
        }
×
3148
        r.server.cc.Wallet.CancelRebroadcast(*txid)
3✔
3149

3✔
3150
        // Abandoning a channel is a three-step process: remove from the open
3✔
3151
        // channel state, remove from the graph, remove from the contract
3✔
3152
        // court. Between any step it's possible that the users restarts the
3✔
3153
        // process all over again. As a result, each of the steps below are
3✔
3154
        // intended to be idempotent.
3✔
3155
        err = r.server.chanStateDB.AbandonChannel(chanPoint, bestHeight)
3✔
3156
        if err != nil {
3✔
3157
                return err
×
3158
        }
×
3159
        err = abandonChanFromGraph(r.server.graphDB, chanPoint)
3✔
3160
        if err != nil {
3✔
3161
                return err
×
3162
        }
×
3163
        err = r.server.chainArb.ResolveContract(*chanPoint)
3✔
3164
        if err != nil {
3✔
3165
                return err
×
3166
        }
×
3167

3168
        // If this channel was in the process of being closed, but didn't fully
3169
        // close, then it's possible that the nursery is hanging on to some
3170
        // state. To err on the side of caution, we'll now attempt to wipe any
3171
        // state for this channel from the nursery.
3172
        err = r.server.utxoNursery.RemoveChannel(chanPoint)
3✔
3173
        if err != nil && err != contractcourt.ErrContractNotFound {
3✔
3174
                return err
×
3175
        }
×
3176

3177
        // Finally, notify the backup listeners that the channel can be removed
3178
        // from any channel backups.
3179
        r.server.channelNotifier.NotifyClosedChannelEvent(*chanPoint)
3✔
3180

3✔
3181
        return nil
3✔
3182
}
3183

3184
// AbandonChannel removes all channel state from the database except for a
3185
// close summary. This method can be used to get rid of permanently unusable
3186
// channels due to bugs fixed in newer versions of lnd.
3187
func (r *rpcServer) AbandonChannel(_ context.Context,
3188
        in *lnrpc.AbandonChannelRequest) (*lnrpc.AbandonChannelResponse, error) {
3✔
3189

3✔
3190
        // If this isn't the dev build, then we won't allow the RPC to be
3✔
3191
        // executed, as it's an advanced feature and won't be activated in
3✔
3192
        // regular production/release builds except for the explicit case of
3✔
3193
        // externally funded channels that are still pending. Due to repeated
3✔
3194
        // requests, we also allow this requirement to be overwritten by a new
3✔
3195
        // flag that attests to the user knowing what they're doing and the risk
3✔
3196
        // associated with the command/RPC.
3✔
3197
        if !in.IKnowWhatIAmDoing && !in.PendingFundingShimOnly &&
3✔
3198
                !build.IsDevBuild() {
3✔
3199

×
3200
                return nil, fmt.Errorf("AbandonChannel RPC call only " +
×
3201
                        "available in dev builds")
×
3202
        }
×
3203

3204
        // We'll parse out the arguments to we can obtain the chanPoint of the
3205
        // target channel.
3206
        txid, err := lnrpc.GetChanPointFundingTxid(in.GetChannelPoint())
3✔
3207
        if err != nil {
3✔
3208
                return nil, err
×
3209
        }
×
3210
        index := in.ChannelPoint.OutputIndex
3✔
3211
        chanPoint := wire.NewOutPoint(txid, index)
3✔
3212

3✔
3213
        // When we remove the channel from the database, we need to set a close
3✔
3214
        // height, so we'll just use the current best known height.
3✔
3215
        _, bestHeight, err := r.server.cc.ChainIO.GetBestBlock()
3✔
3216
        if err != nil {
3✔
3217
                return nil, err
×
3218
        }
×
3219

3220
        dbChan, err := r.server.chanStateDB.FetchChannel(*chanPoint)
3✔
3221
        switch {
3✔
3222
        // If the channel isn't found in the set of open channels, then we can
3223
        // continue on as it can't be loaded into the link/peer.
3224
        case err == channeldb.ErrChannelNotFound:
3✔
3225
                break
3✔
3226

3227
        // If the channel is still known to be open, then before we modify any
3228
        // on-disk state, we'll remove the channel from the switch and peer
3229
        // state if it's been loaded in.
3230
        case err == nil:
3✔
3231
                // If the user requested the more safe version that only allows
3✔
3232
                // the removal of externally (shim) funded channels that are
3✔
3233
                // still pending, we enforce this option now that we know the
3✔
3234
                // state of the channel.
3✔
3235
                //
3✔
3236
                // TODO(guggero): Properly store the funding type (wallet, shim,
3✔
3237
                // PSBT) on the channel so we don't need to use the thaw height.
3✔
3238
                isShimFunded := dbChan.ThawHeight > 0
3✔
3239
                isPendingShimFunded := isShimFunded && dbChan.IsPending
3✔
3240
                if !in.IKnowWhatIAmDoing && in.PendingFundingShimOnly &&
3✔
3241
                        !isPendingShimFunded {
3✔
3242

×
3243
                        return nil, fmt.Errorf("channel %v is not externally "+
×
3244
                                "funded or not pending", chanPoint)
×
3245
                }
×
3246

3247
                // We'll mark the channel as borked before we remove the state
3248
                // from the switch/peer so it won't be loaded back in if the
3249
                // peer reconnects.
3250
                if err := dbChan.MarkBorked(); err != nil {
3✔
3251
                        return nil, err
×
3252
                }
×
3253
                remotePub := dbChan.IdentityPub
3✔
3254
                if peer, err := r.server.FindPeer(remotePub); err == nil {
6✔
3255
                        peer.WipeChannel(chanPoint)
3✔
3256
                }
3✔
3257

3258
        default:
×
3259
                return nil, err
×
3260
        }
3261

3262
        // Remove the channel from the graph, database and contract court.
3263
        if err := r.abandonChan(chanPoint, uint32(bestHeight)); err != nil {
3✔
3264
                return nil, err
×
3265
        }
×
3266

3267
        return &lnrpc.AbandonChannelResponse{
3✔
3268
                Status: fmt.Sprintf("channel %v abandoned", chanPoint.String()),
3✔
3269
        }, nil
3✔
3270
}
3271

3272
// GetInfo returns general information concerning the lightning node including
3273
// its identity pubkey, alias, the chains it is connected to, and information
3274
// concerning the number of open+pending channels.
3275
func (r *rpcServer) GetInfo(_ context.Context,
3276
        _ *lnrpc.GetInfoRequest) (*lnrpc.GetInfoResponse, error) {
3✔
3277

3✔
3278
        serverPeers := r.server.Peers()
3✔
3279

3✔
3280
        openChannels, err := r.server.chanStateDB.FetchAllOpenChannels()
3✔
3281
        if err != nil {
3✔
3282
                return nil, err
×
3283
        }
×
3284

3285
        var activeChannels uint32
3✔
3286
        for _, channel := range openChannels {
6✔
3287
                chanID := lnwire.NewChanIDFromOutPoint(channel.FundingOutpoint)
3✔
3288
                if r.server.htlcSwitch.HasActiveLink(chanID) {
6✔
3289
                        activeChannels++
3✔
3290
                }
3✔
3291
        }
3292

3293
        inactiveChannels := uint32(len(openChannels)) - activeChannels
3✔
3294

3✔
3295
        pendingChannels, err := r.server.chanStateDB.FetchPendingChannels()
3✔
3296
        if err != nil {
3✔
3297
                return nil, fmt.Errorf("unable to get retrieve pending "+
×
3298
                        "channels: %v", err)
×
3299
        }
×
3300
        nPendingChannels := uint32(len(pendingChannels))
3✔
3301

3✔
3302
        idPub := r.server.identityECDH.PubKey().SerializeCompressed()
3✔
3303
        encodedIDPub := hex.EncodeToString(idPub)
3✔
3304

3✔
3305
        // Get the system's chain sync info.
3✔
3306
        syncInfo, err := r.getChainSyncInfo()
3✔
3307
        if err != nil {
3✔
3308
                return nil, err
×
3309
        }
×
3310

3311
        network := lncfg.NormalizeNetwork(r.cfg.ActiveNetParams.Name)
3✔
3312
        activeChains := []*lnrpc.Chain{
3✔
3313
                {
3✔
3314
                        Chain:   BitcoinChainName,
3✔
3315
                        Network: network,
3✔
3316
                },
3✔
3317
        }
3✔
3318

3✔
3319
        // Check if external IP addresses were provided to lnd and use them
3✔
3320
        // to set the URIs.
3✔
3321
        nodeAnn := r.server.getNodeAnnouncement()
3✔
3322

3✔
3323
        addrs := nodeAnn.Addresses
3✔
3324
        uris := make([]string, len(addrs))
3✔
3325
        for i, addr := range addrs {
6✔
3326
                uris[i] = fmt.Sprintf("%s@%s", encodedIDPub, addr.String())
3✔
3327
        }
3✔
3328

3329
        isGraphSynced := r.server.authGossiper.SyncManager().IsGraphSynced()
3✔
3330

3✔
3331
        features := make(map[uint32]*lnrpc.Feature)
3✔
3332
        sets := r.server.featureMgr.ListSets()
3✔
3333

3✔
3334
        for _, set := range sets {
6✔
3335
                // Get the a list of lnrpc features for each set we support.
3✔
3336
                featureVector := r.server.featureMgr.Get(set)
3✔
3337
                rpcFeatures := invoicesrpc.CreateRPCFeatures(featureVector)
3✔
3338

3✔
3339
                // Add the features to our map of features, allowing over writing of
3✔
3340
                // existing values because features in different sets with the same bit
3✔
3341
                // are duplicated across sets.
3✔
3342
                maps.Copy(features, rpcFeatures)
3✔
3343
        }
3✔
3344

3345
        // TODO(roasbeef): add synced height n stuff
3346

3347
        isTestNet := chainreg.IsTestnet(&r.cfg.ActiveNetParams)
3✔
3348
        nodeColor := graphdb.EncodeHexColor(nodeAnn.RGBColor)
3✔
3349
        version := build.Version() + " commit=" + build.Commit
3✔
3350

3✔
3351
        return &lnrpc.GetInfoResponse{
3✔
3352
                IdentityPubkey:            encodedIDPub,
3✔
3353
                NumPendingChannels:        nPendingChannels,
3✔
3354
                NumActiveChannels:         activeChannels,
3✔
3355
                NumInactiveChannels:       inactiveChannels,
3✔
3356
                NumPeers:                  uint32(len(serverPeers)),
3✔
3357
                BlockHeight:               uint32(syncInfo.bestHeight),
3✔
3358
                BlockHash:                 syncInfo.blockHash.String(),
3✔
3359
                SyncedToChain:             syncInfo.isSynced,
3✔
3360
                Testnet:                   isTestNet,
3✔
3361
                Chains:                    activeChains,
3✔
3362
                Uris:                      uris,
3✔
3363
                Alias:                     nodeAnn.Alias.String(),
3✔
3364
                Color:                     nodeColor,
3✔
3365
                BestHeaderTimestamp:       syncInfo.timestamp,
3✔
3366
                Version:                   version,
3✔
3367
                CommitHash:                build.CommitHash,
3✔
3368
                SyncedToGraph:             isGraphSynced,
3✔
3369
                Features:                  features,
3✔
3370
                RequireHtlcInterceptor:    r.cfg.RequireInterceptor,
3✔
3371
                StoreFinalHtlcResolutions: r.cfg.StoreFinalHtlcResolutions,
3✔
3372
        }, nil
3✔
3373
}
3374

3375
// GetDebugInfo returns debug information concerning the state of the daemon
3376
// and its subsystems. This includes the full configuration and the latest log
3377
// entries from the log file.
3378
func (r *rpcServer) GetDebugInfo(_ context.Context,
3379
        _ *lnrpc.GetDebugInfoRequest) (*lnrpc.GetDebugInfoResponse, error) {
×
3380

×
3381
        flatConfig, _, err := configToFlatMap(*r.cfg)
×
3382
        if err != nil {
×
3383
                return nil, fmt.Errorf("error converting config to flat map: "+
×
3384
                        "%w", err)
×
3385
        }
×
3386

3387
        logFileName := filepath.Join(r.cfg.LogDir, defaultLogFilename)
×
3388
        logContent, err := os.ReadFile(logFileName)
×
3389
        if err != nil {
×
3390
                return nil, fmt.Errorf("error reading log file '%s': %w",
×
3391
                        logFileName, err)
×
3392
        }
×
3393

3394
        return &lnrpc.GetDebugInfoResponse{
×
3395
                Config: flatConfig,
×
3396
                Log:    strings.Split(string(logContent), "\n"),
×
3397
        }, nil
×
3398
}
3399

3400
// GetRecoveryInfo returns a boolean indicating whether the wallet is started
3401
// in recovery mode, whether the recovery is finished, and the progress made
3402
// so far.
3403
func (r *rpcServer) GetRecoveryInfo(ctx context.Context,
3404
        in *lnrpc.GetRecoveryInfoRequest) (*lnrpc.GetRecoveryInfoResponse, error) {
3✔
3405

3✔
3406
        isRecoveryMode, progress, err := r.server.cc.Wallet.GetRecoveryInfo()
3✔
3407
        if err != nil {
3✔
3408
                return nil, fmt.Errorf("unable to get wallet recovery info: %w",
×
3409
                        err)
×
3410
        }
×
3411

3412
        rpcsLog.Debugf("[getrecoveryinfo] is recovery mode=%v, progress=%v",
3✔
3413
                isRecoveryMode, progress)
3✔
3414

3✔
3415
        return &lnrpc.GetRecoveryInfoResponse{
3✔
3416
                RecoveryMode:     isRecoveryMode,
3✔
3417
                RecoveryFinished: progress == 1,
3✔
3418
                Progress:         progress,
3✔
3419
        }, nil
3✔
3420
}
3421

3422
// ListPeers returns a verbose listing of all currently active peers.
3423
func (r *rpcServer) ListPeers(ctx context.Context,
3424
        in *lnrpc.ListPeersRequest) (*lnrpc.ListPeersResponse, error) {
3✔
3425

3✔
3426
        serverPeers := r.server.Peers()
3✔
3427
        resp := &lnrpc.ListPeersResponse{
3✔
3428
                Peers: make([]*lnrpc.Peer, 0, len(serverPeers)),
3✔
3429
        }
3✔
3430

3✔
3431
        for _, serverPeer := range serverPeers {
6✔
3432
                var (
3✔
3433
                        satSent int64
3✔
3434
                        satRecv int64
3✔
3435
                )
3✔
3436

3✔
3437
                // In order to display the total number of satoshis of outbound
3✔
3438
                // (sent) and inbound (recv'd) satoshis that have been
3✔
3439
                // transported through this peer, we'll sum up the sent/recv'd
3✔
3440
                // values for each of the active channels we have with the
3✔
3441
                // peer.
3✔
3442
                chans := serverPeer.ChannelSnapshots()
3✔
3443
                for _, c := range chans {
6✔
3444
                        satSent += int64(c.TotalMSatSent.ToSatoshis())
3✔
3445
                        satRecv += int64(c.TotalMSatReceived.ToSatoshis())
3✔
3446
                }
3✔
3447

3448
                nodePub := serverPeer.PubKey()
3✔
3449

3✔
3450
                // Retrieve the peer's sync type. If we don't currently have a
3✔
3451
                // syncer for the peer, then we'll default to a passive sync.
3✔
3452
                // This can happen if the RPC is called while a peer is
3✔
3453
                // initializing.
3✔
3454
                syncer, ok := r.server.authGossiper.SyncManager().GossipSyncer(
3✔
3455
                        nodePub,
3✔
3456
                )
3✔
3457

3✔
3458
                var lnrpcSyncType lnrpc.Peer_SyncType
3✔
3459
                if !ok {
3✔
3460
                        rpcsLog.Warnf("Gossip syncer for peer=%x not found",
×
3461
                                nodePub)
×
3462
                        lnrpcSyncType = lnrpc.Peer_UNKNOWN_SYNC
×
3463
                } else {
3✔
3464
                        syncType := syncer.SyncType()
3✔
3465
                        switch syncType {
3✔
3466
                        case discovery.ActiveSync:
3✔
3467
                                lnrpcSyncType = lnrpc.Peer_ACTIVE_SYNC
3✔
3468
                        case discovery.PassiveSync:
3✔
3469
                                lnrpcSyncType = lnrpc.Peer_PASSIVE_SYNC
3✔
3470
                        case discovery.PinnedSync:
3✔
3471
                                lnrpcSyncType = lnrpc.Peer_PINNED_SYNC
3✔
3472
                        default:
×
3473
                                return nil, fmt.Errorf("unhandled sync type %v",
×
3474
                                        syncType)
×
3475
                        }
3476
                }
3477

3478
                features := invoicesrpc.CreateRPCFeatures(
3✔
3479
                        serverPeer.RemoteFeatures(),
3✔
3480
                )
3✔
3481

3✔
3482
                rpcPeer := &lnrpc.Peer{
3✔
3483
                        PubKey:          hex.EncodeToString(nodePub[:]),
3✔
3484
                        Address:         serverPeer.Conn().RemoteAddr().String(),
3✔
3485
                        Inbound:         serverPeer.Inbound(),
3✔
3486
                        BytesRecv:       serverPeer.BytesReceived(),
3✔
3487
                        BytesSent:       serverPeer.BytesSent(),
3✔
3488
                        SatSent:         satSent,
3✔
3489
                        SatRecv:         satRecv,
3✔
3490
                        PingTime:        serverPeer.PingTime(),
3✔
3491
                        SyncType:        lnrpcSyncType,
3✔
3492
                        Features:        features,
3✔
3493
                        LastPingPayload: serverPeer.LastRemotePingPayload(),
3✔
3494
                }
3✔
3495

3✔
3496
                var peerErrors []interface{}
3✔
3497

3✔
3498
                // If we only want the most recent error, get the most recent
3✔
3499
                // error from the buffer and add it to our list of errors if
3✔
3500
                // it is non-nil. If we want all the stored errors, simply
3✔
3501
                // add the full list to our set of errors.
3✔
3502
                if in.LatestError {
3✔
3503
                        latestErr := serverPeer.ErrorBuffer().Latest()
×
3504
                        if latestErr != nil {
×
3505
                                peerErrors = []interface{}{latestErr}
×
3506
                        }
×
3507
                } else {
3✔
3508
                        peerErrors = serverPeer.ErrorBuffer().List()
3✔
3509
                }
3✔
3510

3511
                // Add the relevant peer errors to our response.
3512
                for _, error := range peerErrors {
6✔
3513
                        tsError := error.(*peer.TimestampedError)
3✔
3514

3✔
3515
                        rpcErr := &lnrpc.TimestampedError{
3✔
3516
                                Timestamp: uint64(tsError.Timestamp.Unix()),
3✔
3517
                                Error:     tsError.Error.Error(),
3✔
3518
                        }
3✔
3519

3✔
3520
                        rpcPeer.Errors = append(rpcPeer.Errors, rpcErr)
3✔
3521
                }
3✔
3522

3523
                // If the server has started, we can query the event store
3524
                // for our peer's flap count. If we do so when the server has
3525
                // not started, the request will block.
3526
                if r.server.Started() {
6✔
3527
                        vertex, err := route.NewVertexFromBytes(nodePub[:])
3✔
3528
                        if err != nil {
3✔
3529
                                return nil, err
×
3530
                        }
×
3531

3532
                        flap, ts, err := r.server.chanEventStore.FlapCount(
3✔
3533
                                vertex,
3✔
3534
                        )
3✔
3535
                        if err != nil {
3✔
3536
                                return nil, err
×
3537
                        }
×
3538

3539
                        // If our timestamp is non-nil, we have values for our
3540
                        // peer's flap count, so we set them.
3541
                        if ts != nil {
6✔
3542
                                rpcPeer.FlapCount = int32(flap)
3✔
3543
                                rpcPeer.LastFlapNs = ts.UnixNano()
3✔
3544
                        }
3✔
3545
                }
3546

3547
                resp.Peers = append(resp.Peers, rpcPeer)
3✔
3548
        }
3549

3550
        rpcsLog.Debugf("[listpeers] yielded %v peers", serverPeers)
3✔
3551

3✔
3552
        return resp, nil
3✔
3553
}
3554

3555
// SubscribePeerEvents returns a uni-directional stream (server -> client)
3556
// for notifying the client of peer online and offline events.
3557
func (r *rpcServer) SubscribePeerEvents(req *lnrpc.PeerEventSubscription,
3558
        eventStream lnrpc.Lightning_SubscribePeerEventsServer) error {
3✔
3559

3✔
3560
        peerEventSub, err := r.server.peerNotifier.SubscribePeerEvents()
3✔
3561
        if err != nil {
3✔
3562
                return err
×
3563
        }
×
3564
        defer peerEventSub.Cancel()
3✔
3565

3✔
3566
        for {
6✔
3567
                select {
3✔
3568
                // A new update has been sent by the peer notifier, we'll
3569
                // marshal it into the form expected by the gRPC client, then
3570
                // send it off to the client.
3571
                case e := <-peerEventSub.Updates():
3✔
3572
                        var event *lnrpc.PeerEvent
3✔
3573

3✔
3574
                        switch peerEvent := e.(type) {
3✔
3575
                        case peernotifier.PeerOfflineEvent:
3✔
3576
                                event = &lnrpc.PeerEvent{
3✔
3577
                                        PubKey: hex.EncodeToString(peerEvent.PubKey[:]),
3✔
3578
                                        Type:   lnrpc.PeerEvent_PEER_OFFLINE,
3✔
3579
                                }
3✔
3580

3581
                        case peernotifier.PeerOnlineEvent:
×
3582
                                event = &lnrpc.PeerEvent{
×
3583
                                        PubKey: hex.EncodeToString(peerEvent.PubKey[:]),
×
3584
                                        Type:   lnrpc.PeerEvent_PEER_ONLINE,
×
3585
                                }
×
3586

3587
                        default:
×
3588
                                return fmt.Errorf("unexpected peer event: %v", event)
×
3589
                        }
3590

3591
                        if err := eventStream.Send(event); err != nil {
3✔
3592
                                return err
×
3593
                        }
×
3594

3595
                // The response stream's context for whatever reason has been
3596
                // closed. If context is closed by an exceeded deadline we will
3597
                // return an error.
3598
                case <-eventStream.Context().Done():
3✔
3599
                        if errors.Is(eventStream.Context().Err(), context.Canceled) {
6✔
3600
                                return nil
3✔
3601
                        }
3✔
3602
                        return eventStream.Context().Err()
×
3603

3604
                case <-r.quit:
×
3605
                        return nil
×
3606
                }
3607
        }
3608
}
3609

3610
// WalletBalance returns total unspent outputs(confirmed and unconfirmed), all
3611
// confirmed unspent outputs and all unconfirmed unspent outputs under control
3612
// by the wallet. This method can be modified by having the request specify
3613
// only witness outputs should be factored into the final output sum.
3614
// TODO(roasbeef): add async hooks into wallet balance changes.
3615
func (r *rpcServer) WalletBalance(ctx context.Context,
3616
        in *lnrpc.WalletBalanceRequest) (*lnrpc.WalletBalanceResponse, error) {
3✔
3617

3✔
3618
        // Retrieve all existing wallet accounts. We'll compute the confirmed
3✔
3619
        // and unconfirmed balance for each and tally them up.
3✔
3620
        accounts, err := r.server.cc.Wallet.ListAccounts(in.Account, nil)
3✔
3621
        if err != nil {
3✔
3622
                return nil, err
×
3623
        }
×
3624

3625
        var totalBalance, confirmedBalance, unconfirmedBalance btcutil.Amount
3✔
3626
        rpcAccountBalances := make(
3✔
3627
                map[string]*lnrpc.WalletAccountBalance, len(accounts),
3✔
3628
        )
3✔
3629
        for _, account := range accounts {
6✔
3630
                // There are two default accounts, one for NP2WKH outputs and
3✔
3631
                // another for P2WKH outputs. The balance will be computed for
3✔
3632
                // both given one call to ConfirmedBalance with the default
3✔
3633
                // wallet and imported account, so we'll skip the second
3✔
3634
                // instance to avoid inflating the balance.
3✔
3635
                switch account.AccountName {
3✔
3636
                case waddrmgr.ImportedAddrAccountName:
3✔
3637
                        // Omit the imported account from the response unless we
3✔
3638
                        // actually have any keys imported.
3✔
3639
                        if account.ImportedKeyCount == 0 {
6✔
3640
                                continue
3✔
3641
                        }
3642

3643
                        fallthrough
3✔
3644

3645
                case lnwallet.DefaultAccountName:
3✔
3646
                        if _, ok := rpcAccountBalances[account.AccountName]; ok {
6✔
3647
                                continue
3✔
3648
                        }
3649

3650
                default:
3✔
3651
                }
3652

3653
                // There now also are the accounts for the internal channel
3654
                // related keys. We skip those as they'll never have any direct
3655
                // balance.
3656
                if account.KeyScope.Purpose == keychain.BIP0043Purpose {
6✔
3657
                        continue
3✔
3658
                }
3659

3660
                // Get total balance, from txs that have >= 0 confirmations.
3661
                totalBal, err := r.server.cc.Wallet.ConfirmedBalance(
3✔
3662
                        0, account.AccountName,
3✔
3663
                )
3✔
3664
                if err != nil {
3✔
3665
                        return nil, err
×
3666
                }
×
3667
                totalBalance += totalBal
3✔
3668

3✔
3669
                // Get confirmed balance, from txs that have >= 1 confirmations.
3✔
3670
                // TODO(halseth): get both unconfirmed and confirmed balance in
3✔
3671
                // one call, as this is racy.
3✔
3672
                if in.MinConfs <= 0 {
6✔
3673
                        in.MinConfs = 1
3✔
3674
                }
3✔
3675
                confirmedBal, err := r.server.cc.Wallet.ConfirmedBalance(
3✔
3676
                        in.MinConfs, account.AccountName,
3✔
3677
                )
3✔
3678
                if err != nil {
3✔
3679
                        return nil, err
×
3680
                }
×
3681
                confirmedBalance += confirmedBal
3✔
3682

3✔
3683
                // Get unconfirmed balance, from txs with 0 confirmations.
3✔
3684
                unconfirmedBal := totalBal - confirmedBal
3✔
3685
                unconfirmedBalance += unconfirmedBal
3✔
3686

3✔
3687
                rpcAccountBalances[account.AccountName] = &lnrpc.WalletAccountBalance{
3✔
3688
                        ConfirmedBalance:   int64(confirmedBal),
3✔
3689
                        UnconfirmedBalance: int64(unconfirmedBal),
3✔
3690
                }
3✔
3691
        }
3692

3693
        // Now that we have the base balance accounted for with each account,
3694
        // we'll look at the set of locked UTXOs to tally that as well. If we
3695
        // don't display this, then anytime we attempt a funding reservation,
3696
        // the outputs will chose as being "gone" until they're confirmed on
3697
        // chain.
3698
        var lockedBalance btcutil.Amount
3✔
3699
        leases, err := r.server.cc.Wallet.ListLeasedOutputs()
3✔
3700
        if err != nil {
3✔
3701
                return nil, err
×
3702
        }
×
3703
        for _, leasedOutput := range leases {
6✔
3704
                lockedBalance += btcutil.Amount(leasedOutput.Value)
3✔
3705
        }
3✔
3706

3707
        // Get the current number of non-private anchor channels.
3708
        currentNumAnchorChans, err := r.server.cc.Wallet.CurrentNumAnchorChans()
3✔
3709
        if err != nil {
3✔
3710
                return nil, err
×
3711
        }
×
3712

3713
        // Get the required reserve for the wallet.
3714
        requiredReserve := r.server.cc.Wallet.RequiredReserve(
3✔
3715
                uint32(currentNumAnchorChans),
3✔
3716
        )
3✔
3717

3✔
3718
        rpcsLog.Debugf("[walletbalance] Total balance=%v (confirmed=%v, "+
3✔
3719
                "unconfirmed=%v)", totalBalance, confirmedBalance,
3✔
3720
                unconfirmedBalance)
3✔
3721

3✔
3722
        return &lnrpc.WalletBalanceResponse{
3✔
3723
                TotalBalance:              int64(totalBalance),
3✔
3724
                ConfirmedBalance:          int64(confirmedBalance),
3✔
3725
                UnconfirmedBalance:        int64(unconfirmedBalance),
3✔
3726
                LockedBalance:             int64(lockedBalance),
3✔
3727
                ReservedBalanceAnchorChan: int64(requiredReserve),
3✔
3728
                AccountBalance:            rpcAccountBalances,
3✔
3729
        }, nil
3✔
3730
}
3731

3732
// ChannelBalance returns the total available channel flow across all open
3733
// channels in satoshis.
3734
func (r *rpcServer) ChannelBalance(ctx context.Context,
3735
        in *lnrpc.ChannelBalanceRequest) (
3736
        *lnrpc.ChannelBalanceResponse, error) {
3✔
3737

3✔
3738
        var (
3✔
3739
                localBalance             lnwire.MilliSatoshi
3✔
3740
                remoteBalance            lnwire.MilliSatoshi
3✔
3741
                unsettledLocalBalance    lnwire.MilliSatoshi
3✔
3742
                unsettledRemoteBalance   lnwire.MilliSatoshi
3✔
3743
                pendingOpenLocalBalance  lnwire.MilliSatoshi
3✔
3744
                pendingOpenRemoteBalance lnwire.MilliSatoshi
3✔
3745
                customDataBuf            bytes.Buffer
3✔
3746
        )
3✔
3747

3✔
3748
        openChannels, err := r.server.chanStateDB.FetchAllOpenChannels()
3✔
3749
        if err != nil {
3✔
3750
                return nil, err
×
3751
        }
×
3752

3753
        // Encode the number of open channels to the custom data buffer.
3754
        err = wire.WriteVarInt(&customDataBuf, 0, uint64(len(openChannels)))
3✔
3755
        if err != nil {
3✔
3756
                return nil, err
×
3757
        }
×
3758

3759
        for _, channel := range openChannels {
6✔
3760
                c := channel.LocalCommitment
3✔
3761
                localBalance += c.LocalBalance
3✔
3762
                remoteBalance += c.RemoteBalance
3✔
3763

3✔
3764
                // Add pending htlc amount.
3✔
3765
                for _, htlc := range c.Htlcs {
6✔
3766
                        if htlc.Incoming {
6✔
3767
                                unsettledLocalBalance += htlc.Amt
3✔
3768
                        } else {
6✔
3769
                                unsettledRemoteBalance += htlc.Amt
3✔
3770
                        }
3✔
3771
                }
3772

3773
                // Encode the custom data for this open channel.
3774
                openChanData := channel.LocalCommitment.CustomBlob.UnwrapOr(nil)
3✔
3775
                err = wire.WriteVarBytes(&customDataBuf, 0, openChanData)
3✔
3776
                if err != nil {
3✔
3777
                        return nil, err
×
3778
                }
×
3779
        }
3780

3781
        pendingChannels, err := r.server.chanStateDB.FetchPendingChannels()
3✔
3782
        if err != nil {
3✔
3783
                return nil, err
×
3784
        }
×
3785

3786
        // Encode the number of pending channels to the custom data buffer.
3787
        err = wire.WriteVarInt(&customDataBuf, 0, uint64(len(pendingChannels)))
3✔
3788
        if err != nil {
3✔
3789
                return nil, err
×
3790
        }
×
3791

3792
        for _, channel := range pendingChannels {
6✔
3793
                c := channel.LocalCommitment
3✔
3794
                pendingOpenLocalBalance += c.LocalBalance
3✔
3795
                pendingOpenRemoteBalance += c.RemoteBalance
3✔
3796

3✔
3797
                // Encode the custom data for this pending channel.
3✔
3798
                openChanData := channel.LocalCommitment.CustomBlob.UnwrapOr(nil)
3✔
3799
                err = wire.WriteVarBytes(&customDataBuf, 0, openChanData)
3✔
3800
                if err != nil {
3✔
3801
                        return nil, err
×
3802
                }
×
3803
        }
3804

3805
        rpcsLog.Debugf("[channelbalance] local_balance=%v remote_balance=%v "+
3✔
3806
                "unsettled_local_balance=%v unsettled_remote_balance=%v "+
3✔
3807
                "pending_open_local_balance=%v pending_open_remote_balance=%v",
3✔
3808
                localBalance, remoteBalance, unsettledLocalBalance,
3✔
3809
                unsettledRemoteBalance, pendingOpenLocalBalance,
3✔
3810
                pendingOpenRemoteBalance)
3✔
3811

3✔
3812
        resp := &lnrpc.ChannelBalanceResponse{
3✔
3813
                LocalBalance: &lnrpc.Amount{
3✔
3814
                        Sat:  uint64(localBalance.ToSatoshis()),
3✔
3815
                        Msat: uint64(localBalance),
3✔
3816
                },
3✔
3817
                RemoteBalance: &lnrpc.Amount{
3✔
3818
                        Sat:  uint64(remoteBalance.ToSatoshis()),
3✔
3819
                        Msat: uint64(remoteBalance),
3✔
3820
                },
3✔
3821
                UnsettledLocalBalance: &lnrpc.Amount{
3✔
3822
                        Sat:  uint64(unsettledLocalBalance.ToSatoshis()),
3✔
3823
                        Msat: uint64(unsettledLocalBalance),
3✔
3824
                },
3✔
3825
                UnsettledRemoteBalance: &lnrpc.Amount{
3✔
3826
                        Sat:  uint64(unsettledRemoteBalance.ToSatoshis()),
3✔
3827
                        Msat: uint64(unsettledRemoteBalance),
3✔
3828
                },
3✔
3829
                PendingOpenLocalBalance: &lnrpc.Amount{
3✔
3830
                        Sat:  uint64(pendingOpenLocalBalance.ToSatoshis()),
3✔
3831
                        Msat: uint64(pendingOpenLocalBalance),
3✔
3832
                },
3✔
3833
                PendingOpenRemoteBalance: &lnrpc.Amount{
3✔
3834
                        Sat:  uint64(pendingOpenRemoteBalance.ToSatoshis()),
3✔
3835
                        Msat: uint64(pendingOpenRemoteBalance),
3✔
3836
                },
3✔
3837
                CustomChannelData: customDataBuf.Bytes(),
3✔
3838

3✔
3839
                // Deprecated fields.
3✔
3840
                Balance:            int64(localBalance.ToSatoshis()),
3✔
3841
                PendingOpenBalance: int64(pendingOpenLocalBalance.ToSatoshis()),
3✔
3842
        }
3✔
3843

3✔
3844
        err = fn.MapOptionZ(
3✔
3845
                r.server.implCfg.AuxDataParser,
3✔
3846
                func(parser AuxDataParser) error {
3✔
UNCOV
3847
                        return parser.InlineParseCustomData(resp)
×
UNCOV
3848
                },
×
3849
        )
3850
        if err != nil {
3✔
3851
                return nil, fmt.Errorf("error parsing custom data: %w", err)
×
3852
        }
×
3853

3854
        return resp, nil
3✔
3855
}
3856

3857
type (
3858
        pendingOpenChannels  []*lnrpc.PendingChannelsResponse_PendingOpenChannel
3859
        pendingForceClose    []*lnrpc.PendingChannelsResponse_ForceClosedChannel
3860
        waitingCloseChannels []*lnrpc.PendingChannelsResponse_WaitingCloseChannel
3861
)
3862

3863
// fetchPendingOpenChannels queries the database for a list of channels that
3864
// have pending open state. The returned result is used in the response of the
3865
// PendingChannels RPC.
3866
func (r *rpcServer) fetchPendingOpenChannels() (pendingOpenChannels, error) {
3✔
3867
        // First, we'll populate the response with all the channels that are
3✔
3868
        // soon to be opened. We can easily fetch this data from the database
3✔
3869
        // and map the db struct to the proto response.
3✔
3870
        channels, err := r.server.chanStateDB.FetchPendingChannels()
3✔
3871
        if err != nil {
3✔
3872
                rpcsLog.Errorf("unable to fetch pending channels: %v", err)
×
3873
                return nil, err
×
3874
        }
×
3875

3876
        _, currentHeight, err := r.server.cc.ChainIO.GetBestBlock()
3✔
3877
        if err != nil {
3✔
3878
                return nil, err
×
3879
        }
×
3880

3881
        result := make(pendingOpenChannels, len(channels))
3✔
3882
        for i, pendingChan := range channels {
6✔
3883
                pub := pendingChan.IdentityPub.SerializeCompressed()
3✔
3884

3✔
3885
                // As this is required for display purposes, we'll calculate
3✔
3886
                // the weight of the commitment transaction. We also add on the
3✔
3887
                // estimated weight of the witness to calculate the weight of
3✔
3888
                // the transaction if it were to be immediately unilaterally
3✔
3889
                // broadcast.
3✔
3890
                // TODO(roasbeef): query for funding tx from wallet, display
3✔
3891
                // that also?
3✔
3892
                var witnessWeight int64
3✔
3893
                if pendingChan.ChanType.IsTaproot() {
6✔
3894
                        witnessWeight = input.TaprootKeyPathWitnessSize
3✔
3895
                } else {
6✔
3896
                        witnessWeight = input.WitnessCommitmentTxWeight
3✔
3897
                }
3✔
3898

3899
                localCommitment := pendingChan.LocalCommitment
3✔
3900
                utx := btcutil.NewTx(localCommitment.CommitTx)
3✔
3901
                commitBaseWeight := blockchain.GetTransactionWeight(utx)
3✔
3902
                commitWeight := commitBaseWeight + witnessWeight
3✔
3903

3✔
3904
                // The value of waitBlocksForFundingConf is adjusted in a
3✔
3905
                // development environment to enhance test capabilities.
3✔
3906
                // Otherwise, it is set to DefaultMaxWaitNumBlocksFundingConf.
3✔
3907
                waitBlocksForFundingConf := uint32(
3✔
3908
                        lncfg.DefaultMaxWaitNumBlocksFundingConf,
3✔
3909
                )
3✔
3910

3✔
3911
                if lncfg.IsDevBuild() {
6✔
3912
                        waitBlocksForFundingConf =
3✔
3913
                                r.cfg.Dev.GetMaxWaitNumBlocksFundingConf()
3✔
3914
                }
3✔
3915

3916
                // FundingExpiryBlocks is the distance from the current block
3917
                // height to the broadcast height + waitBlocksForFundingConf.
3918
                maxFundingHeight := waitBlocksForFundingConf +
3✔
3919
                        pendingChan.BroadcastHeight()
3✔
3920
                fundingExpiryBlocks := int32(maxFundingHeight) - currentHeight
3✔
3921

3✔
3922
                customChanBytes, err := encodeCustomChanData(pendingChan)
3✔
3923
                if err != nil {
3✔
3924
                        return nil, fmt.Errorf("unable to encode open chan "+
×
3925
                                "data: %w", err)
×
3926
                }
×
3927

3928
                result[i] = &lnrpc.PendingChannelsResponse_PendingOpenChannel{
3✔
3929
                        Channel: &lnrpc.PendingChannelsResponse_PendingChannel{
3✔
3930
                                RemoteNodePub:        hex.EncodeToString(pub),
3✔
3931
                                ChannelPoint:         pendingChan.FundingOutpoint.String(),
3✔
3932
                                Capacity:             int64(pendingChan.Capacity),
3✔
3933
                                LocalBalance:         int64(localCommitment.LocalBalance.ToSatoshis()),
3✔
3934
                                RemoteBalance:        int64(localCommitment.RemoteBalance.ToSatoshis()),
3✔
3935
                                LocalChanReserveSat:  int64(pendingChan.LocalChanCfg.ChanReserve),
3✔
3936
                                RemoteChanReserveSat: int64(pendingChan.RemoteChanCfg.ChanReserve),
3✔
3937
                                Initiator:            rpcInitiator(pendingChan.IsInitiator),
3✔
3938
                                CommitmentType:       rpcCommitmentType(pendingChan.ChanType),
3✔
3939
                                Private:              isPrivate(pendingChan),
3✔
3940
                                Memo:                 string(pendingChan.Memo),
3✔
3941
                                CustomChannelData:    customChanBytes,
3✔
3942
                        },
3✔
3943
                        CommitWeight:        commitWeight,
3✔
3944
                        CommitFee:           int64(localCommitment.CommitFee),
3✔
3945
                        FeePerKw:            int64(localCommitment.FeePerKw),
3✔
3946
                        FundingExpiryBlocks: fundingExpiryBlocks,
3✔
3947
                        // TODO(roasbeef): need to track confirmation height
3✔
3948
                }
3✔
3949
        }
3950

3951
        return result, nil
3✔
3952
}
3953

3954
// fetchPendingForceCloseChannels queries the database for a list of channels
3955
// that have their closing transactions confirmed but not fully resolved yet.
3956
// The returned result is used in the response of the PendingChannels RPC.
3957
func (r *rpcServer) fetchPendingForceCloseChannels() (pendingForceClose,
3958
        int64, error) {
3✔
3959

3✔
3960
        _, currentHeight, err := r.server.cc.ChainIO.GetBestBlock()
3✔
3961
        if err != nil {
3✔
3962
                return nil, 0, err
×
3963
        }
×
3964

3965
        // Next, we'll examine the channels that are soon to be closed so we
3966
        // can populate these fields within the response.
3967
        channels, err := r.server.chanStateDB.FetchClosedChannels(true)
3✔
3968
        if err != nil {
3✔
3969
                rpcsLog.Errorf("unable to fetch closed channels: %v", err)
×
3970
                return nil, 0, err
×
3971
        }
×
3972

3973
        result := make(pendingForceClose, 0)
3✔
3974
        limboBalance := int64(0)
3✔
3975

3✔
3976
        for _, pendingClose := range channels {
6✔
3977
                // First construct the channel struct itself, this will be
3✔
3978
                // needed regardless of how this channel was closed.
3✔
3979
                pub := pendingClose.RemotePub.SerializeCompressed()
3✔
3980
                chanPoint := pendingClose.ChanPoint
3✔
3981

3✔
3982
                // Create the pending channel. If this channel was closed before
3✔
3983
                // we started storing historical channel data, we will not know
3✔
3984
                // who initiated the channel, so we set the initiator field to
3✔
3985
                // unknown.
3✔
3986
                channel := &lnrpc.PendingChannelsResponse_PendingChannel{
3✔
3987
                        RemoteNodePub:  hex.EncodeToString(pub),
3✔
3988
                        ChannelPoint:   chanPoint.String(),
3✔
3989
                        Capacity:       int64(pendingClose.Capacity),
3✔
3990
                        LocalBalance:   int64(pendingClose.SettledBalance),
3✔
3991
                        CommitmentType: lnrpc.CommitmentType_UNKNOWN_COMMITMENT_TYPE,
3✔
3992
                        Initiator:      lnrpc.Initiator_INITIATOR_UNKNOWN,
3✔
3993
                }
3✔
3994

3✔
3995
                // Lookup the channel in the historical channel bucket to obtain
3✔
3996
                // initiator information. If the historical channel bucket was
3✔
3997
                // not found, or the channel itself, this channel was closed
3✔
3998
                // in a version before we started persisting historical
3✔
3999
                // channels, so we silence the error.
3✔
4000
                historical, err := r.server.chanStateDB.FetchHistoricalChannel(
3✔
4001
                        &pendingClose.ChanPoint,
3✔
4002
                )
3✔
4003
                switch err {
3✔
4004
                // If the channel was closed in a version that did not record
4005
                // historical channels, ignore the error.
4006
                case channeldb.ErrNoHistoricalBucket:
×
4007
                case channeldb.ErrChannelNotFound:
×
4008

4009
                case nil:
3✔
4010
                        channel.Initiator = rpcInitiator(historical.IsInitiator)
3✔
4011
                        channel.CommitmentType = rpcCommitmentType(
3✔
4012
                                historical.ChanType,
3✔
4013
                        )
3✔
4014

3✔
4015
                        // Get the number of forwarding packages from the
3✔
4016
                        // historical channel.
3✔
4017
                        fwdPkgs, err := historical.LoadFwdPkgs()
3✔
4018
                        if err != nil {
3✔
4019
                                rpcsLog.Errorf("unable to load forwarding "+
×
4020
                                        "packages for channel:%s, %v",
×
4021
                                        historical.ShortChannelID, err)
×
4022
                                return nil, 0, err
×
4023
                        }
×
4024
                        channel.NumForwardingPackages = int64(len(fwdPkgs))
3✔
4025

3✔
4026
                        channel.RemoteBalance = int64(
3✔
4027
                                historical.LocalCommitment.RemoteBalance.ToSatoshis(),
3✔
4028
                        )
3✔
4029

3✔
4030
                        customChanBytes, err := encodeCustomChanData(historical)
3✔
4031
                        if err != nil {
3✔
4032
                                return nil, 0, fmt.Errorf("unable to encode "+
×
4033
                                        "open chan data: %w", err)
×
4034
                        }
×
4035
                        channel.CustomChannelData = customChanBytes
3✔
4036

3✔
4037
                        channel.Private = isPrivate(historical)
3✔
4038
                        channel.Memo = string(historical.Memo)
3✔
4039

4040
                // If the error is non-nil, and not due to older versions of lnd
4041
                // not persisting historical channels, return it.
4042
                default:
×
4043
                        return nil, 0, err
×
4044
                }
4045

4046
                closeTXID := pendingClose.ClosingTXID.String()
3✔
4047

3✔
4048
                switch pendingClose.CloseType {
3✔
4049

4050
                // A coop closed channel should never be in the "pending close"
4051
                // state. If a node upgraded from an older lnd version in the
4052
                // middle of a their channel confirming, it will be in this
4053
                // state. We log a warning that the channel will not be included
4054
                // in the now deprecated pending close channels field.
4055
                case channeldb.CooperativeClose:
×
4056
                        rpcsLog.Warnf("channel %v cooperatively closed and "+
×
4057
                                "in pending close state",
×
4058
                                pendingClose.ChanPoint)
×
4059

4060
                // If the channel was force closed, then we'll need to query
4061
                // the utxoNursery for additional information.
4062
                // TODO(halseth): distinguish remote and local case?
4063
                case channeldb.LocalForceClose, channeldb.RemoteForceClose:
3✔
4064
                        forceClose := &lnrpc.PendingChannelsResponse_ForceClosedChannel{
3✔
4065
                                Channel:     channel,
3✔
4066
                                ClosingTxid: closeTXID,
3✔
4067
                        }
3✔
4068

3✔
4069
                        // Fetch reports from both nursery and resolvers. At the
3✔
4070
                        // moment this is not an atomic snapshot. This is
3✔
4071
                        // planned to be resolved when the nursery is removed
3✔
4072
                        // and channel arbitrator will be the single source for
3✔
4073
                        // these kind of reports.
3✔
4074
                        err := r.nurseryPopulateForceCloseResp(
3✔
4075
                                &chanPoint, currentHeight, forceClose,
3✔
4076
                        )
3✔
4077
                        if err != nil {
3✔
4078
                                rpcsLog.Errorf("unable to populate nursery "+
×
4079
                                        "force close resp:%s, %v",
×
4080
                                        chanPoint, err)
×
4081
                                return nil, 0, err
×
4082
                        }
×
4083

4084
                        err = r.arbitratorPopulateForceCloseResp(
3✔
4085
                                &chanPoint, currentHeight, forceClose,
3✔
4086
                        )
3✔
4087
                        if err != nil {
3✔
4088
                                rpcsLog.Errorf("unable to populate arbitrator "+
×
4089
                                        "force close resp:%s, %v",
×
4090
                                        chanPoint, err)
×
4091
                                return nil, 0, err
×
4092
                        }
×
4093

4094
                        limboBalance += forceClose.LimboBalance
3✔
4095
                        result = append(result, forceClose)
3✔
4096
                }
4097
        }
4098

4099
        return result, limboBalance, nil
3✔
4100
}
4101

4102
// fetchWaitingCloseChannels queries the database for a list of channels
4103
// that have their closing transactions broadcast but not confirmed yet.
4104
// The returned result is used in the response of the PendingChannels RPC.
4105
func (r *rpcServer) fetchWaitingCloseChannels(
4106
        includeRawTx bool) (waitingCloseChannels, int64, error) {
3✔
4107

3✔
4108
        // We'll also fetch all channels that are open, but have had their
3✔
4109
        // commitment broadcasted, meaning they are waiting for the closing
3✔
4110
        // transaction to confirm.
3✔
4111
        channels, err := r.server.chanStateDB.FetchWaitingCloseChannels()
3✔
4112
        if err != nil {
3✔
4113
                rpcsLog.Errorf("unable to fetch channels waiting close: %v",
×
4114
                        err)
×
4115
                return nil, 0, err
×
4116
        }
×
4117

4118
        result := make(waitingCloseChannels, 0)
3✔
4119
        limboBalance := int64(0)
3✔
4120

3✔
4121
        // getClosingTx is a helper closure that tries to find the closing tx of
3✔
4122
        // a given waiting close channel. Notice that if the remote closes the
3✔
4123
        // channel, we may not have the closing tx.
3✔
4124
        getClosingTx := func(c *channeldb.OpenChannel) (*wire.MsgTx, error) {
6✔
4125
                var (
3✔
4126
                        tx  *wire.MsgTx
3✔
4127
                        err error
3✔
4128
                )
3✔
4129

3✔
4130
                // First, we try to locate the force closing tx. If not found,
3✔
4131
                // we will then try to find its coop closing tx.
3✔
4132
                tx, err = c.BroadcastedCommitment()
3✔
4133
                if err == nil {
6✔
4134
                        return tx, nil
3✔
4135
                }
3✔
4136

4137
                // If the error returned is not ErrNoCloseTx, something
4138
                // unexpected happened and we will return the error.
4139
                if err != channeldb.ErrNoCloseTx {
3✔
4140
                        return nil, err
×
4141
                }
×
4142

4143
                // Otherwise, we continue to locate its coop closing tx.
4144
                tx, err = c.BroadcastedCooperative()
3✔
4145
                if err == nil {
6✔
4146
                        return tx, nil
3✔
4147
                }
3✔
4148

4149
                // Return the error if it's not ErrNoCloseTx.
4150
                if err != channeldb.ErrNoCloseTx {
3✔
4151
                        return nil, err
×
4152
                }
×
4153

4154
                // Otherwise return an empty tx. This can happen if the remote
4155
                // broadcast the closing tx and we haven't recorded it yet.
4156
                return nil, nil
3✔
4157
        }
4158

4159
        for _, waitingClose := range channels {
6✔
4160
                pub := waitingClose.IdentityPub.SerializeCompressed()
3✔
4161
                chanPoint := waitingClose.FundingOutpoint
3✔
4162

3✔
4163
                var commitments lnrpc.PendingChannelsResponse_Commitments
3✔
4164

3✔
4165
                // Report local commit. May not be present when DLP is active.
3✔
4166
                if waitingClose.LocalCommitment.CommitTx != nil {
6✔
4167
                        commitments.LocalTxid =
3✔
4168
                                waitingClose.LocalCommitment.CommitTx.TxHash().
3✔
4169
                                        String()
3✔
4170

3✔
4171
                        commitments.LocalCommitFeeSat = uint64(
3✔
4172
                                waitingClose.LocalCommitment.CommitFee,
3✔
4173
                        )
3✔
4174
                }
3✔
4175

4176
                // Report remote commit. May not be present when DLP is active.
4177
                if waitingClose.RemoteCommitment.CommitTx != nil {
6✔
4178
                        commitments.RemoteTxid =
3✔
4179
                                waitingClose.RemoteCommitment.CommitTx.TxHash().
3✔
4180
                                        String()
3✔
4181

3✔
4182
                        commitments.RemoteCommitFeeSat = uint64(
3✔
4183
                                waitingClose.RemoteCommitment.CommitFee,
3✔
4184
                        )
3✔
4185
                }
3✔
4186

4187
                // Report the remote pending commit if any.
4188
                remoteCommitDiff, err := waitingClose.RemoteCommitChainTip()
3✔
4189

3✔
4190
                switch {
3✔
4191
                // Don't set hash if there is no pending remote commit.
4192
                case err == channeldb.ErrNoPendingCommit:
3✔
4193

4194
                // An unexpected error occurred.
4195
                case err != nil:
×
4196
                        return nil, 0, err
×
4197

4198
                // There is a pending remote commit. Set its hash in the
4199
                // response.
4200
                default:
×
4201
                        hash := remoteCommitDiff.Commitment.CommitTx.TxHash()
×
4202
                        commitments.RemotePendingTxid = hash.String()
×
4203
                        commitments.RemoteCommitFeeSat = uint64(
×
4204
                                remoteCommitDiff.Commitment.CommitFee,
×
4205
                        )
×
4206
                }
4207

4208
                fwdPkgs, err := waitingClose.LoadFwdPkgs()
3✔
4209
                if err != nil {
3✔
4210
                        rpcsLog.Errorf("unable to load forwarding packages "+
×
4211
                                "for channel:%s, %v",
×
4212
                                waitingClose.ShortChannelID, err)
×
4213
                        return nil, 0, err
×
4214
                }
×
4215

4216
                // Get the closing tx.
4217
                // NOTE: the closing tx could be nil here if it's the remote
4218
                // that broadcasted the closing tx.
4219
                closingTx, err := getClosingTx(waitingClose)
3✔
4220
                if err != nil {
3✔
4221
                        rpcsLog.Errorf("unable to find closing tx for "+
×
4222
                                "channel:%s, %v",
×
4223
                                waitingClose.ShortChannelID, err)
×
4224
                        return nil, 0, err
×
4225
                }
×
4226

4227
                customChanBytes, err := encodeCustomChanData(waitingClose)
3✔
4228
                if err != nil {
3✔
4229
                        return nil, 0, fmt.Errorf("unable to encode "+
×
4230
                                "open chan data: %w", err)
×
4231
                }
×
4232

4233
                localCommit := waitingClose.LocalCommitment
3✔
4234
                chanStatus := waitingClose.ChanStatus()
3✔
4235
                channel := &lnrpc.PendingChannelsResponse_PendingChannel{
3✔
4236
                        RemoteNodePub: hex.EncodeToString(pub),
3✔
4237
                        ChannelPoint:  chanPoint.String(),
3✔
4238
                        Capacity:      int64(waitingClose.Capacity),
3✔
4239
                        LocalBalance: int64(
3✔
4240
                                localCommit.LocalBalance.ToSatoshis(),
3✔
4241
                        ),
3✔
4242
                        RemoteBalance: int64(
3✔
4243
                                localCommit.RemoteBalance.ToSatoshis(),
3✔
4244
                        ),
3✔
4245
                        LocalChanReserveSat: int64(
3✔
4246
                                waitingClose.LocalChanCfg.ChanReserve,
3✔
4247
                        ),
3✔
4248
                        RemoteChanReserveSat: int64(
3✔
4249
                                waitingClose.RemoteChanCfg.ChanReserve,
3✔
4250
                        ),
3✔
4251
                        Initiator: rpcInitiator(
3✔
4252
                                waitingClose.IsInitiator,
3✔
4253
                        ),
3✔
4254
                        CommitmentType: rpcCommitmentType(
3✔
4255
                                waitingClose.ChanType,
3✔
4256
                        ),
3✔
4257
                        NumForwardingPackages: int64(len(fwdPkgs)),
3✔
4258
                        ChanStatusFlags:       chanStatus.String(),
3✔
4259
                        Private:               isPrivate(waitingClose),
3✔
4260
                        Memo:                  string(waitingClose.Memo),
3✔
4261
                        CustomChannelData:     customChanBytes,
3✔
4262
                }
3✔
4263

3✔
4264
                var closingTxid, closingTxHex string
3✔
4265
                if closingTx != nil {
6✔
4266
                        closingTxid = closingTx.TxHash().String()
3✔
4267
                        if includeRawTx {
6✔
4268
                                var txBuf bytes.Buffer
3✔
4269
                                err = closingTx.Serialize(&txBuf)
3✔
4270
                                if err != nil {
3✔
4271
                                        return nil, 0, fmt.Errorf("failed to "+
×
4272
                                                "serialize closing transaction"+
×
4273
                                                ": %w", err)
×
4274
                                }
×
4275
                                closingTxHex = hex.EncodeToString(txBuf.Bytes())
3✔
4276
                        }
4277
                }
4278

4279
                waitingCloseResp := &lnrpc.PendingChannelsResponse_WaitingCloseChannel{
3✔
4280
                        Channel:      channel,
3✔
4281
                        LimboBalance: channel.LocalBalance,
3✔
4282
                        Commitments:  &commitments,
3✔
4283
                        ClosingTxid:  closingTxid,
3✔
4284
                        ClosingTxHex: closingTxHex,
3✔
4285
                }
3✔
4286

3✔
4287
                // A close tx has been broadcasted, all our balance will be in
3✔
4288
                // limbo until it confirms.
3✔
4289
                result = append(result, waitingCloseResp)
3✔
4290
                limboBalance += channel.LocalBalance
3✔
4291
        }
4292

4293
        return result, limboBalance, nil
3✔
4294
}
4295

4296
// PendingChannels returns a list of all the channels that are currently
4297
// considered "pending". A channel is pending if it has finished the funding
4298
// workflow and is waiting for confirmations for the funding txn, or is in the
4299
// process of closure, either initiated cooperatively or non-cooperatively.
4300
func (r *rpcServer) PendingChannels(ctx context.Context,
4301
        in *lnrpc.PendingChannelsRequest) (
4302
        *lnrpc.PendingChannelsResponse, error) {
3✔
4303

3✔
4304
        resp := &lnrpc.PendingChannelsResponse{}
3✔
4305

3✔
4306
        // First, we find all the channels that will soon be opened.
3✔
4307
        pendingOpenChannels, err := r.fetchPendingOpenChannels()
3✔
4308
        if err != nil {
3✔
4309
                return nil, err
×
4310
        }
×
4311
        resp.PendingOpenChannels = pendingOpenChannels
3✔
4312

3✔
4313
        // Second, we fetch all channels that considered pending force closing.
3✔
4314
        // This means the channels here have their closing transactions
3✔
4315
        // confirmed but not considered fully resolved yet. For instance, they
3✔
4316
        // may have a second level HTLCs to be resolved onchain.
3✔
4317
        pendingCloseChannels, limbo, err := r.fetchPendingForceCloseChannels()
3✔
4318
        if err != nil {
3✔
4319
                return nil, err
×
4320
        }
×
4321
        resp.PendingForceClosingChannels = pendingCloseChannels
3✔
4322
        resp.TotalLimboBalance = limbo
3✔
4323

3✔
4324
        // Third, we fetch all channels that are open, but have had their
3✔
4325
        // commitment broadcasted, meaning they are waiting for the closing
3✔
4326
        // transaction to confirm.
3✔
4327
        waitingCloseChannels, limbo, err := r.fetchWaitingCloseChannels(
3✔
4328
                in.IncludeRawTx,
3✔
4329
        )
3✔
4330
        if err != nil {
3✔
4331
                return nil, err
×
4332
        }
×
4333
        resp.WaitingCloseChannels = waitingCloseChannels
3✔
4334
        resp.TotalLimboBalance += limbo
3✔
4335

3✔
4336
        err = fn.MapOptionZ(
3✔
4337
                r.server.implCfg.AuxDataParser,
3✔
4338
                func(parser AuxDataParser) error {
3✔
4339
                        return parser.InlineParseCustomData(resp)
×
4340
                },
×
4341
        )
4342
        if err != nil {
3✔
4343
                return nil, fmt.Errorf("error parsing custom data: %w", err)
×
4344
        }
×
4345

4346
        return resp, nil
3✔
4347
}
4348

4349
// arbitratorPopulateForceCloseResp populates the pending channels response
4350
// message with channel resolution information from the contract resolvers.
4351
func (r *rpcServer) arbitratorPopulateForceCloseResp(chanPoint *wire.OutPoint,
4352
        currentHeight int32,
4353
        forceClose *lnrpc.PendingChannelsResponse_ForceClosedChannel) error {
3✔
4354

3✔
4355
        // Query for contract resolvers state.
3✔
4356
        arbitrator, err := r.server.chainArb.GetChannelArbitrator(*chanPoint)
3✔
4357
        if err != nil {
3✔
4358
                return err
×
4359
        }
×
4360
        reports := arbitrator.Report()
3✔
4361

3✔
4362
        for _, report := range reports {
6✔
4363
                switch report.Type {
3✔
4364
                // For a direct output, populate/update the top level
4365
                // response properties.
4366
                case contractcourt.ReportOutputUnencumbered:
3✔
4367
                        // Populate the maturity height fields for the direct
3✔
4368
                        // commitment output to us.
3✔
4369
                        forceClose.MaturityHeight = report.MaturityHeight
3✔
4370

3✔
4371
                        // If the transaction has been confirmed, then we can
3✔
4372
                        // compute how many blocks it has left.
3✔
4373
                        if forceClose.MaturityHeight != 0 {
6✔
4374
                                forceClose.BlocksTilMaturity =
3✔
4375
                                        int32(forceClose.MaturityHeight) -
3✔
4376
                                                currentHeight
3✔
4377
                        }
3✔
4378

4379
                // Add htlcs to the PendingHtlcs response property.
4380
                case contractcourt.ReportOutputIncomingHtlc,
4381
                        contractcourt.ReportOutputOutgoingHtlc:
3✔
4382

3✔
4383
                        // Don't report details on htlcs that are no longer in
3✔
4384
                        // limbo.
3✔
4385
                        if report.LimboBalance == 0 {
3✔
4386
                                break
×
4387
                        }
4388

4389
                        incoming := report.Type == contractcourt.ReportOutputIncomingHtlc
3✔
4390
                        htlc := &lnrpc.PendingHTLC{
3✔
4391
                                Incoming:       incoming,
3✔
4392
                                Amount:         int64(report.Amount),
3✔
4393
                                Outpoint:       report.Outpoint.String(),
3✔
4394
                                MaturityHeight: report.MaturityHeight,
3✔
4395
                                Stage:          report.Stage,
3✔
4396
                        }
3✔
4397

3✔
4398
                        if htlc.MaturityHeight != 0 {
6✔
4399
                                htlc.BlocksTilMaturity =
3✔
4400
                                        int32(htlc.MaturityHeight) - currentHeight
3✔
4401
                        }
3✔
4402

4403
                        forceClose.PendingHtlcs = append(forceClose.PendingHtlcs, htlc)
3✔
4404

4405
                case contractcourt.ReportOutputAnchor:
3✔
4406
                        // There are three resolution states for the anchor:
3✔
4407
                        // limbo, lost and recovered. Derive the current state
3✔
4408
                        // from the limbo and recovered balances.
3✔
4409
                        switch {
3✔
4410
                        case report.RecoveredBalance != 0:
3✔
4411
                                forceClose.Anchor = lnrpc.PendingChannelsResponse_ForceClosedChannel_RECOVERED
3✔
4412

4413
                        case report.LimboBalance != 0:
3✔
4414
                                forceClose.Anchor = lnrpc.PendingChannelsResponse_ForceClosedChannel_LIMBO
3✔
4415

4416
                        default:
3✔
4417
                                forceClose.Anchor = lnrpc.PendingChannelsResponse_ForceClosedChannel_LOST
3✔
4418
                        }
4419

4420
                default:
×
4421
                        return fmt.Errorf("unknown report output type: %v",
×
4422
                                report.Type)
×
4423
                }
4424

4425
                forceClose.LimboBalance += int64(report.LimboBalance)
3✔
4426
                forceClose.RecoveredBalance += int64(report.RecoveredBalance)
3✔
4427
        }
4428

4429
        return nil
3✔
4430
}
4431

4432
// nurseryPopulateForceCloseResp populates the pending channels response
4433
// message with contract resolution information from utxonursery.
4434
func (r *rpcServer) nurseryPopulateForceCloseResp(chanPoint *wire.OutPoint,
4435
        currentHeight int32,
4436
        forceClose *lnrpc.PendingChannelsResponse_ForceClosedChannel) error {
3✔
4437

3✔
4438
        // Query for the maturity state for this force closed channel. If we
3✔
4439
        // didn't have any time-locked outputs, then the nursery may not know of
3✔
4440
        // the contract.
3✔
4441
        nurseryInfo, err := r.server.utxoNursery.NurseryReport(chanPoint)
3✔
4442
        if err == contractcourt.ErrContractNotFound {
6✔
4443
                return nil
3✔
4444
        }
3✔
4445
        if err != nil {
×
4446
                return fmt.Errorf("unable to obtain "+
×
4447
                        "nursery report for ChannelPoint(%v): %v",
×
4448
                        chanPoint, err)
×
4449
        }
×
4450

4451
        // If the nursery knows of this channel, then we can populate
4452
        // information detailing exactly how much funds are time locked and also
4453
        // the height in which we can ultimately sweep the funds into the
4454
        // wallet.
4455
        forceClose.LimboBalance = int64(nurseryInfo.LimboBalance)
×
4456
        forceClose.RecoveredBalance = int64(nurseryInfo.RecoveredBalance)
×
4457

×
4458
        for _, htlcReport := range nurseryInfo.Htlcs {
×
4459
                // TODO(conner) set incoming flag appropriately after handling
×
4460
                // incoming incubation
×
4461
                htlc := &lnrpc.PendingHTLC{
×
4462
                        Incoming:       false,
×
4463
                        Amount:         int64(htlcReport.Amount),
×
4464
                        Outpoint:       htlcReport.Outpoint.String(),
×
4465
                        MaturityHeight: htlcReport.MaturityHeight,
×
4466
                        Stage:          htlcReport.Stage,
×
4467
                }
×
4468

×
4469
                if htlc.MaturityHeight != 0 {
×
4470
                        htlc.BlocksTilMaturity =
×
4471
                                int32(htlc.MaturityHeight) -
×
4472
                                        currentHeight
×
4473
                }
×
4474

4475
                forceClose.PendingHtlcs = append(forceClose.PendingHtlcs,
×
4476
                        htlc)
×
4477
        }
4478

4479
        return nil
×
4480
}
4481

4482
// ClosedChannels returns a list of all the channels have been closed.
4483
// This does not include channels that are still in the process of closing.
4484
func (r *rpcServer) ClosedChannels(ctx context.Context,
4485
        in *lnrpc.ClosedChannelsRequest) (*lnrpc.ClosedChannelsResponse,
4486
        error) {
3✔
4487

3✔
4488
        // Show all channels when no filter flags are set.
3✔
4489
        filterResults := in.Cooperative || in.LocalForce ||
3✔
4490
                in.RemoteForce || in.Breach || in.FundingCanceled ||
3✔
4491
                in.Abandoned
3✔
4492

3✔
4493
        resp := &lnrpc.ClosedChannelsResponse{}
3✔
4494

3✔
4495
        dbChannels, err := r.server.chanStateDB.FetchClosedChannels(false)
3✔
4496
        if err != nil {
3✔
4497
                return nil, err
×
4498
        }
×
4499

4500
        // In order to make the response easier to parse for clients, we'll
4501
        // sort the set of closed channels by their closing height before
4502
        // serializing the proto response.
4503
        sort.Slice(dbChannels, func(i, j int) bool {
3✔
4504
                return dbChannels[i].CloseHeight < dbChannels[j].CloseHeight
×
4505
        })
×
4506

4507
        for _, dbChannel := range dbChannels {
6✔
4508
                if dbChannel.IsPending {
3✔
4509
                        continue
×
4510
                }
4511

4512
                switch dbChannel.CloseType {
3✔
4513
                case channeldb.CooperativeClose:
3✔
4514
                        if filterResults && !in.Cooperative {
3✔
4515
                                continue
×
4516
                        }
4517
                case channeldb.LocalForceClose:
3✔
4518
                        if filterResults && !in.LocalForce {
3✔
4519
                                continue
×
4520
                        }
4521
                case channeldb.RemoteForceClose:
3✔
4522
                        if filterResults && !in.RemoteForce {
3✔
4523
                                continue
×
4524
                        }
4525
                case channeldb.BreachClose:
×
4526
                        if filterResults && !in.Breach {
×
4527
                                continue
×
4528
                        }
4529
                case channeldb.FundingCanceled:
×
4530
                        if filterResults && !in.FundingCanceled {
×
4531
                                continue
×
4532
                        }
4533
                case channeldb.Abandoned:
3✔
4534
                        if filterResults && !in.Abandoned {
3✔
4535
                                continue
×
4536
                        }
4537
                }
4538

4539
                channel, err := r.createRPCClosedChannel(dbChannel)
3✔
4540
                if err != nil {
3✔
4541
                        return nil, err
×
4542
                }
×
4543

4544
                resp.Channels = append(resp.Channels, channel)
3✔
4545
        }
4546

4547
        err = fn.MapOptionZ(
3✔
4548
                r.server.implCfg.AuxDataParser,
3✔
4549
                func(parser AuxDataParser) error {
3✔
4550
                        return parser.InlineParseCustomData(resp)
×
4551
                },
×
4552
        )
4553
        if err != nil {
3✔
4554
                return nil, fmt.Errorf("error parsing custom data: %w", err)
×
4555
        }
×
4556

4557
        return resp, nil
3✔
4558
}
4559

4560
// LookupHtlcResolution retrieves a final htlc resolution from the database. If
4561
// the htlc has no final resolution yet, a NotFound grpc status code is
4562
// returned.
4563
func (r *rpcServer) LookupHtlcResolution(
4564
        _ context.Context, in *lnrpc.LookupHtlcResolutionRequest) (
4565
        *lnrpc.LookupHtlcResolutionResponse, error) {
3✔
4566

3✔
4567
        if !r.cfg.StoreFinalHtlcResolutions {
6✔
4568
                return nil, status.Error(codes.Unavailable, "cannot lookup "+
3✔
4569
                        "with flag --store-final-htlc-resolutions=false")
3✔
4570
        }
3✔
4571

4572
        chanID := lnwire.NewShortChanIDFromInt(in.ChanId)
3✔
4573

3✔
4574
        info, err := r.server.chanStateDB.LookupFinalHtlc(chanID, in.HtlcIndex)
3✔
4575
        switch {
3✔
4576
        case errors.Is(err, channeldb.ErrHtlcUnknown):
×
4577
                return nil, status.Error(codes.NotFound, err.Error())
×
4578

4579
        case err != nil:
×
4580
                return nil, err
×
4581
        }
4582

4583
        return &lnrpc.LookupHtlcResolutionResponse{
3✔
4584
                Settled:  info.Settled,
3✔
4585
                Offchain: info.Offchain,
3✔
4586
        }, nil
3✔
4587
}
4588

4589
// ListChannels returns a description of all the open channels that this node
4590
// is a participant in.
4591
func (r *rpcServer) ListChannels(ctx context.Context,
4592
        in *lnrpc.ListChannelsRequest) (*lnrpc.ListChannelsResponse, error) {
3✔
4593

3✔
4594
        if in.ActiveOnly && in.InactiveOnly {
6✔
4595
                return nil, fmt.Errorf("either `active_only` or " +
3✔
4596
                        "`inactive_only` can be set, but not both")
3✔
4597
        }
3✔
4598

4599
        if in.PublicOnly && in.PrivateOnly {
3✔
4600
                return nil, fmt.Errorf("either `public_only` or " +
×
4601
                        "`private_only` can be set, but not both")
×
4602
        }
×
4603

4604
        if len(in.Peer) > 0 && len(in.Peer) != 33 {
3✔
4605
                _, err := route.NewVertexFromBytes(in.Peer)
×
4606
                return nil, fmt.Errorf("invalid `peer` key: %w", err)
×
4607
        }
×
4608

4609
        resp := &lnrpc.ListChannelsResponse{}
3✔
4610

3✔
4611
        dbChannels, err := r.server.chanStateDB.FetchAllOpenChannels()
3✔
4612
        if err != nil {
3✔
4613
                return nil, err
×
4614
        }
×
4615

4616
        rpcsLog.Debugf("[listchannels] fetched %v channels from DB",
3✔
4617
                len(dbChannels))
3✔
4618

3✔
4619
        for _, dbChannel := range dbChannels {
6✔
4620
                nodePub := dbChannel.IdentityPub
3✔
4621
                nodePubBytes := nodePub.SerializeCompressed()
3✔
4622
                chanPoint := dbChannel.FundingOutpoint
3✔
4623

3✔
4624
                // If the caller requested channels for a target node, skip any
3✔
4625
                // that don't match the provided pubkey.
3✔
4626
                if len(in.Peer) > 0 && !bytes.Equal(nodePubBytes, in.Peer) {
6✔
4627
                        continue
3✔
4628
                }
4629

4630
                var peerOnline bool
3✔
4631
                if _, err := r.server.FindPeer(nodePub); err == nil {
6✔
4632
                        peerOnline = true
3✔
4633
                }
3✔
4634

4635
                channelID := lnwire.NewChanIDFromOutPoint(chanPoint)
3✔
4636
                var linkActive bool
3✔
4637
                if link, err := r.server.htlcSwitch.GetLink(channelID); err == nil {
6✔
4638
                        // A channel is only considered active if it is known
3✔
4639
                        // by the switch *and* able to forward
3✔
4640
                        // incoming/outgoing payments.
3✔
4641
                        linkActive = link.EligibleToForward()
3✔
4642
                }
3✔
4643

4644
                // Next, we'll determine whether we should add this channel to
4645
                // our list depending on the type of channels requested to us.
4646
                isActive := peerOnline && linkActive
3✔
4647
                channel, err := createRPCOpenChannel(
3✔
4648
                        r, dbChannel, isActive, in.PeerAliasLookup,
3✔
4649
                )
3✔
4650
                if err != nil {
3✔
4651
                        return nil, err
×
4652
                }
×
4653

4654
                // We'll only skip returning this channel if we were requested
4655
                // for a specific kind and this channel doesn't satisfy it.
4656
                switch {
3✔
4657
                case in.ActiveOnly && !isActive:
3✔
4658
                        continue
3✔
4659
                case in.InactiveOnly && isActive:
×
4660
                        continue
×
4661
                case in.PublicOnly && channel.Private:
×
4662
                        continue
×
4663
                case in.PrivateOnly && !channel.Private:
3✔
4664
                        continue
3✔
4665
                }
4666

4667
                resp.Channels = append(resp.Channels, channel)
3✔
4668
        }
4669

4670
        err = fn.MapOptionZ(
3✔
4671
                r.server.implCfg.AuxDataParser,
3✔
4672
                func(parser AuxDataParser) error {
3✔
4673
                        return parser.InlineParseCustomData(resp)
×
4674
                },
×
4675
        )
4676
        if err != nil {
3✔
4677
                return nil, fmt.Errorf("error parsing custom data: %w", err)
×
4678
        }
×
4679

4680
        return resp, nil
3✔
4681
}
4682

4683
// rpcCommitmentType takes the channel type and converts it to an rpc commitment
4684
// type value.
4685
func rpcCommitmentType(chanType channeldb.ChannelType) lnrpc.CommitmentType {
3✔
4686
        // Extract the commitment type from the channel type flags. We must
3✔
4687
        // first check whether it has anchors, since in that case it would also
3✔
4688
        // be tweakless.
3✔
4689
        switch {
3✔
UNCOV
4690
        case chanType.HasTapscriptRoot():
×
UNCOV
4691
                return lnrpc.CommitmentType_SIMPLE_TAPROOT_OVERLAY
×
4692

4693
        case chanType.IsTaproot():
3✔
4694
                return lnrpc.CommitmentType_SIMPLE_TAPROOT
3✔
4695

4696
        case chanType.HasLeaseExpiration():
3✔
4697
                return lnrpc.CommitmentType_SCRIPT_ENFORCED_LEASE
3✔
4698

4699
        case chanType.HasAnchors():
3✔
4700
                return lnrpc.CommitmentType_ANCHORS
3✔
4701

4702
        case chanType.IsTweakless():
3✔
4703
                return lnrpc.CommitmentType_STATIC_REMOTE_KEY
3✔
4704

4705
        default:
3✔
4706

3✔
4707
                return lnrpc.CommitmentType_LEGACY
3✔
4708
        }
4709
}
4710

4711
// createChannelConstraint creates a *lnrpc.ChannelConstraints using the
4712
// *Channeldb.ChannelConfig.
4713
func createChannelConstraint(
4714
        chanCfg *channeldb.ChannelConfig) *lnrpc.ChannelConstraints {
3✔
4715
        return &lnrpc.ChannelConstraints{
3✔
4716
                CsvDelay:          uint32(chanCfg.CsvDelay),
3✔
4717
                ChanReserveSat:    uint64(chanCfg.ChanReserve),
3✔
4718
                DustLimitSat:      uint64(chanCfg.DustLimit),
3✔
4719
                MaxPendingAmtMsat: uint64(chanCfg.MaxPendingAmount),
3✔
4720
                MinHtlcMsat:       uint64(chanCfg.MinHTLC),
3✔
4721
                MaxAcceptedHtlcs:  uint32(chanCfg.MaxAcceptedHtlcs),
3✔
4722
        }
3✔
4723
}
3✔
4724

4725
// isPrivate evaluates the ChannelFlags of the db channel to determine if the
4726
// channel is private or not.
4727
func isPrivate(dbChannel *channeldb.OpenChannel) bool {
3✔
4728
        if dbChannel == nil {
3✔
4729
                return false
×
4730
        }
×
4731
        return dbChannel.ChannelFlags&lnwire.FFAnnounceChannel != 1
3✔
4732
}
4733

4734
// encodeCustomChanData encodes the custom channel data for the open channel.
4735
// It encodes that data as a pair of var bytes blobs.
4736
func encodeCustomChanData(lnChan *channeldb.OpenChannel) ([]byte, error) {
3✔
4737
        customOpenChanData := lnChan.CustomBlob.UnwrapOr(nil)
3✔
4738
        customLocalCommitData := lnChan.LocalCommitment.CustomBlob.UnwrapOr(nil)
3✔
4739

3✔
4740
        // Don't write any custom data if both blobs are empty.
3✔
4741
        if len(customOpenChanData) == 0 && len(customLocalCommitData) == 0 {
6✔
4742
                return nil, nil
3✔
4743
        }
3✔
4744

4745
        // We'll encode our custom channel data as two blobs. The first is a
4746
        // set of var bytes encoding of the open chan data, the second is an
4747
        // encoding of the local commitment data.
4748
        var customChanDataBuf bytes.Buffer
×
4749
        err := wire.WriteVarBytes(&customChanDataBuf, 0, customOpenChanData)
×
4750
        if err != nil {
×
4751
                return nil, fmt.Errorf("unable to encode open chan "+
×
4752
                        "data: %w", err)
×
4753
        }
×
4754
        err = wire.WriteVarBytes(&customChanDataBuf, 0, customLocalCommitData)
×
4755
        if err != nil {
×
4756
                return nil, fmt.Errorf("unable to encode local commit "+
×
4757
                        "data: %w", err)
×
4758
        }
×
4759

4760
        return customChanDataBuf.Bytes(), nil
×
4761
}
4762

4763
// createRPCOpenChannel creates an *lnrpc.Channel from the *channeldb.Channel.
4764
func createRPCOpenChannel(r *rpcServer, dbChannel *channeldb.OpenChannel,
4765
        isActive, peerAliasLookup bool) (*lnrpc.Channel, error) {
3✔
4766

3✔
4767
        nodePub := dbChannel.IdentityPub
3✔
4768
        nodeID := hex.EncodeToString(nodePub.SerializeCompressed())
3✔
4769
        chanPoint := dbChannel.FundingOutpoint
3✔
4770
        chanID := lnwire.NewChanIDFromOutPoint(chanPoint)
3✔
4771

3✔
4772
        // As this is required for display purposes, we'll calculate
3✔
4773
        // the weight of the commitment transaction. We also add on the
3✔
4774
        // estimated weight of the witness to calculate the weight of
3✔
4775
        // the transaction if it were to be immediately unilaterally
3✔
4776
        // broadcast.
3✔
4777
        var witnessWeight int64
3✔
4778
        if dbChannel.ChanType.IsTaproot() {
6✔
4779
                witnessWeight = input.TaprootKeyPathWitnessSize
3✔
4780
        } else {
6✔
4781
                witnessWeight = input.WitnessCommitmentTxWeight
3✔
4782
        }
3✔
4783

4784
        localCommit := dbChannel.LocalCommitment
3✔
4785
        utx := btcutil.NewTx(localCommit.CommitTx)
3✔
4786
        commitBaseWeight := blockchain.GetTransactionWeight(utx)
3✔
4787
        commitWeight := commitBaseWeight + witnessWeight
3✔
4788

3✔
4789
        localBalance := localCommit.LocalBalance
3✔
4790
        remoteBalance := localCommit.RemoteBalance
3✔
4791

3✔
4792
        // As an artifact of our usage of mSAT internally, either party
3✔
4793
        // may end up in a state where they're holding a fractional
3✔
4794
        // amount of satoshis which can't be expressed within the
3✔
4795
        // actual commitment output. Since we round down when going
3✔
4796
        // from mSAT -> SAT, we may at any point be adding an
3✔
4797
        // additional SAT to miners fees. As a result, we display a
3✔
4798
        // commitment fee that accounts for this externally.
3✔
4799
        var sumOutputs btcutil.Amount
3✔
4800
        for _, txOut := range localCommit.CommitTx.TxOut {
6✔
4801
                sumOutputs += btcutil.Amount(txOut.Value)
3✔
4802
        }
3✔
4803
        externalCommitFee := dbChannel.Capacity - sumOutputs
3✔
4804

3✔
4805
        // Extract the commitment type from the channel type flags.
3✔
4806
        commitmentType := rpcCommitmentType(dbChannel.ChanType)
3✔
4807

3✔
4808
        dbScid := dbChannel.ShortChannelID
3✔
4809

3✔
4810
        // Fetch the set of aliases for the channel.
3✔
4811
        channelAliases := r.server.aliasMgr.GetAliases(dbScid)
3✔
4812

3✔
4813
        // Fetch the peer alias. If one does not exist, errNoPeerAlias
3✔
4814
        // is returned and peerScidAlias will be an empty ShortChannelID.
3✔
4815
        peerScidAlias, _ := r.server.aliasMgr.GetPeerAlias(chanID)
3✔
4816

3✔
4817
        // Finally we'll attempt to encode the custom channel data if any
3✔
4818
        // exists.
3✔
4819
        customChanBytes, err := encodeCustomChanData(dbChannel)
3✔
4820
        if err != nil {
3✔
4821
                return nil, fmt.Errorf("unable to encode open chan data: %w",
×
4822
                        err)
×
4823
        }
×
4824

4825
        channel := &lnrpc.Channel{
3✔
4826
                Active:                isActive,
3✔
4827
                Private:               isPrivate(dbChannel),
3✔
4828
                RemotePubkey:          nodeID,
3✔
4829
                ChannelPoint:          chanPoint.String(),
3✔
4830
                ChanId:                dbScid.ToUint64(),
3✔
4831
                Capacity:              int64(dbChannel.Capacity),
3✔
4832
                LocalBalance:          int64(localBalance.ToSatoshis()),
3✔
4833
                RemoteBalance:         int64(remoteBalance.ToSatoshis()),
3✔
4834
                CommitFee:             int64(externalCommitFee),
3✔
4835
                CommitWeight:          commitWeight,
3✔
4836
                FeePerKw:              int64(localCommit.FeePerKw),
3✔
4837
                TotalSatoshisSent:     int64(dbChannel.TotalMSatSent.ToSatoshis()),
3✔
4838
                TotalSatoshisReceived: int64(dbChannel.TotalMSatReceived.ToSatoshis()),
3✔
4839
                NumUpdates:            localCommit.CommitHeight,
3✔
4840
                PendingHtlcs:          make([]*lnrpc.HTLC, len(localCommit.Htlcs)),
3✔
4841
                Initiator:             dbChannel.IsInitiator,
3✔
4842
                ChanStatusFlags:       dbChannel.ChanStatus().String(),
3✔
4843
                StaticRemoteKey:       commitmentType == lnrpc.CommitmentType_STATIC_REMOTE_KEY,
3✔
4844
                CommitmentType:        commitmentType,
3✔
4845
                ThawHeight:            dbChannel.ThawHeight,
3✔
4846
                LocalConstraints: createChannelConstraint(
3✔
4847
                        &dbChannel.LocalChanCfg,
3✔
4848
                ),
3✔
4849
                RemoteConstraints: createChannelConstraint(
3✔
4850
                        &dbChannel.RemoteChanCfg,
3✔
4851
                ),
3✔
4852
                AliasScids:            make([]uint64, 0, len(channelAliases)),
3✔
4853
                PeerScidAlias:         peerScidAlias.ToUint64(),
3✔
4854
                ZeroConf:              dbChannel.IsZeroConf(),
3✔
4855
                ZeroConfConfirmedScid: dbChannel.ZeroConfRealScid().ToUint64(),
3✔
4856
                Memo:                  string(dbChannel.Memo),
3✔
4857
                CustomChannelData:     customChanBytes,
3✔
4858
                // TODO: remove the following deprecated fields
3✔
4859
                CsvDelay:             uint32(dbChannel.LocalChanCfg.CsvDelay),
3✔
4860
                LocalChanReserveSat:  int64(dbChannel.LocalChanCfg.ChanReserve),
3✔
4861
                RemoteChanReserveSat: int64(dbChannel.RemoteChanCfg.ChanReserve),
3✔
4862
        }
3✔
4863

3✔
4864
        // Look up our channel peer's node alias if the caller requests it.
3✔
4865
        if peerAliasLookup {
6✔
4866
                peerAlias, err := r.server.graphDB.LookupAlias(nodePub)
3✔
4867
                if err != nil {
3✔
4868
                        peerAlias = fmt.Sprintf("unable to lookup "+
×
4869
                                "peer alias: %v", err)
×
4870
                }
×
4871
                channel.PeerAlias = peerAlias
3✔
4872
        }
4873

4874
        // Populate the set of aliases.
4875
        for _, chanAlias := range channelAliases {
6✔
4876
                channel.AliasScids = append(
3✔
4877
                        channel.AliasScids, chanAlias.ToUint64(),
3✔
4878
                )
3✔
4879
        }
3✔
4880

4881
        // Create two sets of the HTLCs found in the remote commitment, which is
4882
        // used to decide whether the HTLCs from the local commitment has been
4883
        // locked in or not.
4884
        remoteIncomingHTLCs := fn.NewSet[uint64]()
3✔
4885
        remoteOutgoingHTLCs := fn.NewSet[uint64]()
3✔
4886
        for _, htlc := range dbChannel.RemoteCommitment.Htlcs {
6✔
4887
                if htlc.Incoming {
6✔
4888
                        remoteIncomingHTLCs.Add(htlc.HtlcIndex)
3✔
4889
                } else {
6✔
4890
                        remoteOutgoingHTLCs.Add(htlc.HtlcIndex)
3✔
4891
                }
3✔
4892
        }
4893

4894
        for i, htlc := range localCommit.Htlcs {
6✔
4895
                var rHash [32]byte
3✔
4896
                copy(rHash[:], htlc.RHash[:])
3✔
4897

3✔
4898
                circuitMap := r.server.htlcSwitch.CircuitLookup()
3✔
4899

3✔
4900
                var (
3✔
4901
                        forwardingChannel, forwardingHtlcIndex uint64
3✔
4902
                        lockedIn                               bool
3✔
4903
                )
3✔
4904
                switch {
3✔
4905
                case htlc.Incoming:
3✔
4906
                        circuit := circuitMap.LookupCircuit(
3✔
4907
                                htlcswitch.CircuitKey{
3✔
4908
                                        ChanID: dbChannel.ShortChannelID,
3✔
4909
                                        HtlcID: htlc.HtlcIndex,
3✔
4910
                                },
3✔
4911
                        )
3✔
4912
                        if circuit != nil && circuit.Outgoing != nil {
6✔
4913
                                forwardingChannel = circuit.Outgoing.ChanID.
3✔
4914
                                        ToUint64()
3✔
4915

3✔
4916
                                forwardingHtlcIndex = circuit.Outgoing.HtlcID
3✔
4917
                        }
3✔
4918

4919
                        lockedIn = remoteIncomingHTLCs.Contains(htlc.HtlcIndex)
3✔
4920

4921
                case !htlc.Incoming:
3✔
4922
                        circuit := circuitMap.LookupOpenCircuit(
3✔
4923
                                htlcswitch.CircuitKey{
3✔
4924
                                        ChanID: dbChannel.ShortChannelID,
3✔
4925
                                        HtlcID: htlc.HtlcIndex,
3✔
4926
                                },
3✔
4927
                        )
3✔
4928

3✔
4929
                        // If the incoming channel id is the special hop.Source
3✔
4930
                        // value, the htlc index is a local payment identifier.
3✔
4931
                        // In this case, report nothing.
3✔
4932
                        if circuit != nil &&
3✔
4933
                                circuit.Incoming.ChanID != hop.Source {
6✔
4934

3✔
4935
                                forwardingChannel = circuit.Incoming.ChanID.
3✔
4936
                                        ToUint64()
3✔
4937

3✔
4938
                                forwardingHtlcIndex = circuit.Incoming.HtlcID
3✔
4939
                        }
3✔
4940

4941
                        lockedIn = remoteOutgoingHTLCs.Contains(htlc.HtlcIndex)
3✔
4942
                }
4943

4944
                channel.PendingHtlcs[i] = &lnrpc.HTLC{
3✔
4945
                        Incoming:            htlc.Incoming,
3✔
4946
                        Amount:              int64(htlc.Amt.ToSatoshis()),
3✔
4947
                        HashLock:            rHash[:],
3✔
4948
                        ExpirationHeight:    htlc.RefundTimeout,
3✔
4949
                        HtlcIndex:           htlc.HtlcIndex,
3✔
4950
                        ForwardingChannel:   forwardingChannel,
3✔
4951
                        ForwardingHtlcIndex: forwardingHtlcIndex,
3✔
4952
                        LockedIn:            lockedIn,
3✔
4953
                }
3✔
4954

3✔
4955
                // Add the Pending Htlc Amount to UnsettledBalance field.
3✔
4956
                channel.UnsettledBalance += channel.PendingHtlcs[i].Amount
3✔
4957
        }
4958

4959
        // If we initiated opening the channel, the zero height remote balance
4960
        // is the push amount. Otherwise, our starting balance is the push
4961
        // amount. If there is no push amount, these values will simply be zero.
4962
        if dbChannel.IsInitiator {
6✔
4963
                amt := dbChannel.InitialRemoteBalance.ToSatoshis()
3✔
4964
                channel.PushAmountSat = uint64(amt)
3✔
4965
        } else {
6✔
4966
                amt := dbChannel.InitialLocalBalance.ToSatoshis()
3✔
4967
                channel.PushAmountSat = uint64(amt)
3✔
4968
        }
3✔
4969

4970
        if len(dbChannel.LocalShutdownScript) > 0 {
6✔
4971
                _, addresses, _, err := txscript.ExtractPkScriptAddrs(
3✔
4972
                        dbChannel.LocalShutdownScript, r.cfg.ActiveNetParams.Params,
3✔
4973
                )
3✔
4974
                if err != nil {
3✔
4975
                        return nil, err
×
4976
                }
×
4977

4978
                // We only expect one upfront shutdown address for a channel. If
4979
                // LocalShutdownScript is non-zero, there should be one payout
4980
                // address set.
4981
                if len(addresses) != 1 {
3✔
4982
                        return nil, fmt.Errorf("expected one upfront shutdown "+
×
4983
                                "address, got: %v", len(addresses))
×
4984
                }
×
4985

4986
                channel.CloseAddress = addresses[0].String()
3✔
4987
        }
4988

4989
        // If the server hasn't fully started yet, it's possible that the
4990
        // channel event store hasn't either, so it won't be able to consume any
4991
        // requests until then. To prevent blocking, we'll just omit the uptime
4992
        // related fields for now.
4993
        if !r.server.Started() {
3✔
4994
                return channel, nil
×
4995
        }
×
4996

4997
        peer, err := route.NewVertexFromBytes(nodePub.SerializeCompressed())
3✔
4998
        if err != nil {
3✔
4999
                return nil, err
×
5000
        }
×
5001

5002
        // Query the event store for additional information about the channel.
5003
        // Do not fail if it is not available, because there is a potential
5004
        // race between a channel being added to our node and the event store
5005
        // being notified of it.
5006
        outpoint := dbChannel.FundingOutpoint
3✔
5007
        info, err := r.server.chanEventStore.GetChanInfo(outpoint, peer)
3✔
5008
        switch err {
3✔
5009
        // If the store does not know about the channel, we just log it.
5010
        case chanfitness.ErrChannelNotFound:
3✔
5011
                rpcsLog.Infof("channel: %v not found by channel event store",
3✔
5012
                        outpoint)
3✔
5013

5014
        // If we got our channel info, we further populate the channel.
5015
        case nil:
3✔
5016
                channel.Uptime = int64(info.Uptime.Seconds())
3✔
5017
                channel.Lifetime = int64(info.Lifetime.Seconds())
3✔
5018

5019
        // If we get an unexpected error, we return it.
5020
        default:
×
5021
                return nil, err
×
5022
        }
5023

5024
        return channel, nil
3✔
5025
}
5026

5027
// createRPCClosedChannel creates an *lnrpc.ClosedChannelSummary from a
5028
// *channeldb.ChannelCloseSummary.
5029
func (r *rpcServer) createRPCClosedChannel(
5030
        dbChannel *channeldb.ChannelCloseSummary) (*lnrpc.ChannelCloseSummary,
5031
        error) {
3✔
5032

3✔
5033
        nodePub := dbChannel.RemotePub
3✔
5034
        nodeID := hex.EncodeToString(nodePub.SerializeCompressed())
3✔
5035

3✔
5036
        var (
3✔
5037
                closeType      lnrpc.ChannelCloseSummary_ClosureType
3✔
5038
                openInit       lnrpc.Initiator
3✔
5039
                closeInitiator lnrpc.Initiator
3✔
5040
                err            error
3✔
5041
        )
3✔
5042

3✔
5043
        // Lookup local and remote cooperative initiators. If these values
3✔
5044
        // are not known they will just return unknown.
3✔
5045
        openInit, closeInitiator, err = r.getInitiators(&dbChannel.ChanPoint)
3✔
5046
        if err != nil {
3✔
5047
                return nil, err
×
5048
        }
×
5049

5050
        // Convert the close type to rpc type.
5051
        switch dbChannel.CloseType {
3✔
5052
        case channeldb.CooperativeClose:
3✔
5053
                closeType = lnrpc.ChannelCloseSummary_COOPERATIVE_CLOSE
3✔
5054
        case channeldb.LocalForceClose:
3✔
5055
                closeType = lnrpc.ChannelCloseSummary_LOCAL_FORCE_CLOSE
3✔
5056
        case channeldb.RemoteForceClose:
3✔
5057
                closeType = lnrpc.ChannelCloseSummary_REMOTE_FORCE_CLOSE
3✔
5058
        case channeldb.BreachClose:
×
5059
                closeType = lnrpc.ChannelCloseSummary_BREACH_CLOSE
×
5060
        case channeldb.FundingCanceled:
×
5061
                closeType = lnrpc.ChannelCloseSummary_FUNDING_CANCELED
×
5062
        case channeldb.Abandoned:
3✔
5063
                closeType = lnrpc.ChannelCloseSummary_ABANDONED
3✔
5064
        }
5065

5066
        dbScid := dbChannel.ShortChanID
3✔
5067

3✔
5068
        // Fetch the set of aliases for this channel.
3✔
5069
        channelAliases := r.server.aliasMgr.GetAliases(dbScid)
3✔
5070

3✔
5071
        channel := &lnrpc.ChannelCloseSummary{
3✔
5072
                Capacity:          int64(dbChannel.Capacity),
3✔
5073
                RemotePubkey:      nodeID,
3✔
5074
                CloseHeight:       dbChannel.CloseHeight,
3✔
5075
                CloseType:         closeType,
3✔
5076
                ChannelPoint:      dbChannel.ChanPoint.String(),
3✔
5077
                ChanId:            dbChannel.ShortChanID.ToUint64(),
3✔
5078
                SettledBalance:    int64(dbChannel.SettledBalance),
3✔
5079
                TimeLockedBalance: int64(dbChannel.TimeLockedBalance),
3✔
5080
                ChainHash:         dbChannel.ChainHash.String(),
3✔
5081
                ClosingTxHash:     dbChannel.ClosingTXID.String(),
3✔
5082
                OpenInitiator:     openInit,
3✔
5083
                CloseInitiator:    closeInitiator,
3✔
5084
                AliasScids:        make([]uint64, 0, len(channelAliases)),
3✔
5085
        }
3✔
5086

3✔
5087
        // Populate the set of aliases.
3✔
5088
        for _, chanAlias := range channelAliases {
3✔
5089
                channel.AliasScids = append(
×
5090
                        channel.AliasScids, chanAlias.ToUint64(),
×
5091
                )
×
5092
        }
×
5093

5094
        // Populate any historical data that the summary needs.
5095
        histChan, err := r.server.chanStateDB.FetchHistoricalChannel(
3✔
5096
                &dbChannel.ChanPoint,
3✔
5097
        )
3✔
5098
        switch err {
3✔
5099
        // The channel was closed in a pre-historic version of lnd. Ignore the
5100
        // error.
5101
        case channeldb.ErrNoHistoricalBucket:
×
5102
        case channeldb.ErrChannelNotFound:
×
5103

5104
        case nil:
3✔
5105
                if histChan.IsZeroConf() && histChan.ZeroConfConfirmed() {
3✔
5106
                        // If the channel was zero-conf, it may have confirmed.
×
5107
                        // Populate the confirmed SCID if so.
×
5108
                        confirmedScid := histChan.ZeroConfRealScid().ToUint64()
×
5109
                        channel.ZeroConfConfirmedScid = confirmedScid
×
5110
                }
×
5111

5112
                // Finally we'll attempt to encode the custom channel data if
5113
                // any exists.
5114
                channel.CustomChannelData, err = encodeCustomChanData(histChan)
3✔
5115
                if err != nil {
3✔
5116
                        return nil, fmt.Errorf("unable to encode open chan "+
×
5117
                                "data: %w", err)
×
5118
                }
×
5119

5120
        // Non-nil error not due to older versions of lnd.
5121
        default:
×
5122
                return nil, err
×
5123
        }
5124

5125
        reports, err := r.server.miscDB.FetchChannelReports(
3✔
5126
                *r.cfg.ActiveNetParams.GenesisHash, &dbChannel.ChanPoint,
3✔
5127
        )
3✔
5128
        switch err {
3✔
5129
        // If the channel does not have its resolver outcomes stored,
5130
        // ignore it.
5131
        case channeldb.ErrNoChainHashBucket:
3✔
5132
                fallthrough
3✔
5133
        case channeldb.ErrNoChannelSummaries:
3✔
5134
                return channel, nil
3✔
5135

5136
        // If there is no error, fallthrough the switch to process reports.
5137
        case nil:
3✔
5138

5139
        // If another error occurred, return it.
5140
        default:
×
5141
                return nil, err
×
5142
        }
5143

5144
        for _, report := range reports {
6✔
5145
                rpcResolution, err := rpcChannelResolution(report)
3✔
5146
                if err != nil {
3✔
5147
                        return nil, err
×
5148
                }
×
5149

5150
                channel.Resolutions = append(channel.Resolutions, rpcResolution)
3✔
5151
        }
5152

5153
        return channel, nil
3✔
5154
}
5155

5156
func rpcChannelResolution(report *channeldb.ResolverReport) (*lnrpc.Resolution,
5157
        error) {
3✔
5158

3✔
5159
        res := &lnrpc.Resolution{
3✔
5160
                AmountSat: uint64(report.Amount),
3✔
5161
                Outpoint:  lnrpc.MarshalOutPoint(&report.OutPoint),
3✔
5162
        }
3✔
5163

3✔
5164
        if report.SpendTxID != nil {
6✔
5165
                res.SweepTxid = report.SpendTxID.String()
3✔
5166
        }
3✔
5167

5168
        switch report.ResolverType {
3✔
5169
        case channeldb.ResolverTypeAnchor:
2✔
5170
                res.ResolutionType = lnrpc.ResolutionType_ANCHOR
2✔
5171

5172
        case channeldb.ResolverTypeIncomingHtlc:
3✔
5173
                res.ResolutionType = lnrpc.ResolutionType_INCOMING_HTLC
3✔
5174

5175
        case channeldb.ResolverTypeOutgoingHtlc:
3✔
5176
                res.ResolutionType = lnrpc.ResolutionType_OUTGOING_HTLC
3✔
5177

5178
        case channeldb.ResolverTypeCommit:
3✔
5179
                res.ResolutionType = lnrpc.ResolutionType_COMMIT
3✔
5180

5181
        default:
×
5182
                return nil, fmt.Errorf("unknown resolver type: %v",
×
5183
                        report.ResolverType)
×
5184
        }
5185

5186
        switch report.ResolverOutcome {
3✔
5187
        case channeldb.ResolverOutcomeClaimed:
3✔
5188
                res.Outcome = lnrpc.ResolutionOutcome_CLAIMED
3✔
5189

5190
        case channeldb.ResolverOutcomeUnclaimed:
×
5191
                res.Outcome = lnrpc.ResolutionOutcome_UNCLAIMED
×
5192

5193
        case channeldb.ResolverOutcomeAbandoned:
×
5194
                res.Outcome = lnrpc.ResolutionOutcome_ABANDONED
×
5195

5196
        case channeldb.ResolverOutcomeFirstStage:
3✔
5197
                res.Outcome = lnrpc.ResolutionOutcome_FIRST_STAGE
3✔
5198

5199
        case channeldb.ResolverOutcomeTimeout:
3✔
5200
                res.Outcome = lnrpc.ResolutionOutcome_TIMEOUT
3✔
5201

5202
        default:
×
5203
                return nil, fmt.Errorf("unknown outcome: %v",
×
5204
                        report.ResolverOutcome)
×
5205
        }
5206

5207
        return res, nil
3✔
5208
}
5209

5210
// getInitiators returns an initiator enum that provides information about the
5211
// party that initiated channel's open and close. This information is obtained
5212
// from the historical channel bucket, so unknown values are returned when the
5213
// channel is not present (which indicates that it was closed before we started
5214
// writing channels to the historical close bucket).
5215
func (r *rpcServer) getInitiators(chanPoint *wire.OutPoint) (
5216
        lnrpc.Initiator,
5217
        lnrpc.Initiator, error) {
3✔
5218

3✔
5219
        var (
3✔
5220
                openInitiator  = lnrpc.Initiator_INITIATOR_UNKNOWN
3✔
5221
                closeInitiator = lnrpc.Initiator_INITIATOR_UNKNOWN
3✔
5222
        )
3✔
5223

3✔
5224
        // To get the close initiator for cooperative closes, we need
3✔
5225
        // to get the channel status from the historical channel bucket.
3✔
5226
        histChan, err := r.server.chanStateDB.FetchHistoricalChannel(chanPoint)
3✔
5227
        switch {
3✔
5228
        // The node has upgraded from a version where we did not store
5229
        // historical channels, and has not closed a channel since. Do
5230
        // not return an error, initiator values are unknown.
5231
        case err == channeldb.ErrNoHistoricalBucket:
×
5232
                return openInitiator, closeInitiator, nil
×
5233

5234
        // The channel was closed before we started storing historical
5235
        // channels. Do  not return an error, initiator values are unknown.
5236
        case err == channeldb.ErrChannelNotFound:
×
5237
                return openInitiator, closeInitiator, nil
×
5238

5239
        case err != nil:
×
5240
                return 0, 0, err
×
5241
        }
5242

5243
        // If we successfully looked up the channel, determine initiator based
5244
        // on channels status.
5245
        if histChan.IsInitiator {
6✔
5246
                openInitiator = lnrpc.Initiator_INITIATOR_LOCAL
3✔
5247
        } else {
6✔
5248
                openInitiator = lnrpc.Initiator_INITIATOR_REMOTE
3✔
5249
        }
3✔
5250

5251
        localInit := histChan.HasChanStatus(
3✔
5252
                channeldb.ChanStatusLocalCloseInitiator,
3✔
5253
        )
3✔
5254

3✔
5255
        remoteInit := histChan.HasChanStatus(
3✔
5256
                channeldb.ChanStatusRemoteCloseInitiator,
3✔
5257
        )
3✔
5258

3✔
5259
        switch {
3✔
5260
        // There is a possible case where closes were attempted by both parties.
5261
        // We return the initiator as both in this case to provide full
5262
        // information about the close.
5263
        case localInit && remoteInit:
×
5264
                closeInitiator = lnrpc.Initiator_INITIATOR_BOTH
×
5265

5266
        case localInit:
3✔
5267
                closeInitiator = lnrpc.Initiator_INITIATOR_LOCAL
3✔
5268

5269
        case remoteInit:
3✔
5270
                closeInitiator = lnrpc.Initiator_INITIATOR_REMOTE
3✔
5271
        }
5272

5273
        return openInitiator, closeInitiator, nil
3✔
5274
}
5275

5276
// SubscribeChannelEvents returns a uni-directional stream (server -> client)
5277
// for notifying the client of newly active, inactive or closed channels.
5278
func (r *rpcServer) SubscribeChannelEvents(req *lnrpc.ChannelEventSubscription,
5279
        updateStream lnrpc.Lightning_SubscribeChannelEventsServer) error {
3✔
5280

3✔
5281
        channelEventSub, err := r.server.channelNotifier.SubscribeChannelEvents()
3✔
5282
        if err != nil {
3✔
5283
                return err
×
5284
        }
×
5285

5286
        // Ensure that the resources for the client is cleaned up once either
5287
        // the server, or client exits.
5288
        defer channelEventSub.Cancel()
3✔
5289

3✔
5290
        for {
6✔
5291
                select {
3✔
5292
                // A new update has been sent by the channel router, we'll
5293
                // marshal it into the form expected by the gRPC client, then
5294
                // send it off to the client(s).
5295
                case e := <-channelEventSub.Updates():
3✔
5296
                        var update *lnrpc.ChannelEventUpdate
3✔
5297
                        switch event := e.(type) {
3✔
5298
                        case channelnotifier.PendingOpenChannelEvent:
3✔
5299
                                update = &lnrpc.ChannelEventUpdate{
3✔
5300
                                        Type: lnrpc.ChannelEventUpdate_PENDING_OPEN_CHANNEL,
3✔
5301
                                        Channel: &lnrpc.ChannelEventUpdate_PendingOpenChannel{
3✔
5302
                                                PendingOpenChannel: &lnrpc.PendingUpdate{
3✔
5303
                                                        Txid:        event.ChannelPoint.Hash[:],
3✔
5304
                                                        OutputIndex: event.ChannelPoint.Index,
3✔
5305
                                                },
3✔
5306
                                        },
3✔
5307
                                }
3✔
5308
                        case channelnotifier.OpenChannelEvent:
3✔
5309
                                channel, err := createRPCOpenChannel(
3✔
5310
                                        r, event.Channel, true, false,
3✔
5311
                                )
3✔
5312
                                if err != nil {
3✔
5313
                                        return err
×
5314
                                }
×
5315

5316
                                update = &lnrpc.ChannelEventUpdate{
3✔
5317
                                        Type: lnrpc.ChannelEventUpdate_OPEN_CHANNEL,
3✔
5318
                                        Channel: &lnrpc.ChannelEventUpdate_OpenChannel{
3✔
5319
                                                OpenChannel: channel,
3✔
5320
                                        },
3✔
5321
                                }
3✔
5322

5323
                        case channelnotifier.ClosedChannelEvent:
3✔
5324
                                closedChannel, err := r.createRPCClosedChannel(
3✔
5325
                                        event.CloseSummary,
3✔
5326
                                )
3✔
5327
                                if err != nil {
3✔
5328
                                        return err
×
5329
                                }
×
5330

5331
                                update = &lnrpc.ChannelEventUpdate{
3✔
5332
                                        Type: lnrpc.ChannelEventUpdate_CLOSED_CHANNEL,
3✔
5333
                                        Channel: &lnrpc.ChannelEventUpdate_ClosedChannel{
3✔
5334
                                                ClosedChannel: closedChannel,
3✔
5335
                                        },
3✔
5336
                                }
3✔
5337

5338
                        case channelnotifier.ActiveChannelEvent:
3✔
5339
                                update = &lnrpc.ChannelEventUpdate{
3✔
5340
                                        Type: lnrpc.ChannelEventUpdate_ACTIVE_CHANNEL,
3✔
5341
                                        Channel: &lnrpc.ChannelEventUpdate_ActiveChannel{
3✔
5342
                                                ActiveChannel: &lnrpc.ChannelPoint{
3✔
5343
                                                        FundingTxid: &lnrpc.ChannelPoint_FundingTxidBytes{
3✔
5344
                                                                FundingTxidBytes: event.ChannelPoint.Hash[:],
3✔
5345
                                                        },
3✔
5346
                                                        OutputIndex: event.ChannelPoint.Index,
3✔
5347
                                                },
3✔
5348
                                        },
3✔
5349
                                }
3✔
5350

5351
                        case channelnotifier.InactiveChannelEvent:
3✔
5352
                                update = &lnrpc.ChannelEventUpdate{
3✔
5353
                                        Type: lnrpc.ChannelEventUpdate_INACTIVE_CHANNEL,
3✔
5354
                                        Channel: &lnrpc.ChannelEventUpdate_InactiveChannel{
3✔
5355
                                                InactiveChannel: &lnrpc.ChannelPoint{
3✔
5356
                                                        FundingTxid: &lnrpc.ChannelPoint_FundingTxidBytes{
3✔
5357
                                                                FundingTxidBytes: event.ChannelPoint.Hash[:],
3✔
5358
                                                        },
3✔
5359
                                                        OutputIndex: event.ChannelPoint.Index,
3✔
5360
                                                },
3✔
5361
                                        },
3✔
5362
                                }
3✔
5363

5364
                        // Completely ignore ActiveLinkEvent and
5365
                        // InactiveLinkEvent as this is explicitly not exposed
5366
                        // to the RPC.
5367
                        case channelnotifier.ActiveLinkEvent,
5368
                                channelnotifier.InactiveLinkEvent:
3✔
5369

3✔
5370
                                continue
3✔
5371

5372
                        case channelnotifier.FullyResolvedChannelEvent:
3✔
5373
                                update = &lnrpc.ChannelEventUpdate{
3✔
5374
                                        Type: lnrpc.ChannelEventUpdate_FULLY_RESOLVED_CHANNEL,
3✔
5375
                                        Channel: &lnrpc.ChannelEventUpdate_FullyResolvedChannel{
3✔
5376
                                                FullyResolvedChannel: &lnrpc.ChannelPoint{
3✔
5377
                                                        FundingTxid: &lnrpc.ChannelPoint_FundingTxidBytes{
3✔
5378
                                                                FundingTxidBytes: event.ChannelPoint.Hash[:],
3✔
5379
                                                        },
3✔
5380
                                                        OutputIndex: event.ChannelPoint.Index,
3✔
5381
                                                },
3✔
5382
                                        },
3✔
5383
                                }
3✔
5384

5385
                        default:
×
5386
                                return fmt.Errorf("unexpected channel event update: %v", event)
×
5387
                        }
5388

5389
                        if err := updateStream.Send(update); err != nil {
3✔
5390
                                return err
×
5391
                        }
×
5392

5393
                // The response stream's context for whatever reason has been
5394
                // closed. If context is closed by an exceeded deadline we will
5395
                // return an error.
5396
                case <-updateStream.Context().Done():
3✔
5397
                        if errors.Is(updateStream.Context().Err(), context.Canceled) {
6✔
5398
                                return nil
3✔
5399
                        }
3✔
5400
                        return updateStream.Context().Err()
×
5401

5402
                case <-r.quit:
×
5403
                        return nil
×
5404
                }
5405
        }
5406
}
5407

5408
// paymentStream enables different types of payment streams, such as:
5409
// lnrpc.Lightning_SendPaymentServer and lnrpc.Lightning_SendToRouteServer to
5410
// execute sendPayment. We use this struct as a sort of bridge to enable code
5411
// re-use between SendPayment and SendToRoute.
5412
type paymentStream struct {
5413
        recv func() (*rpcPaymentRequest, error)
5414
        send func(*lnrpc.SendResponse) error
5415
}
5416

5417
// rpcPaymentRequest wraps lnrpc.SendRequest so that routes from
5418
// lnrpc.SendToRouteRequest can be passed to sendPayment.
5419
type rpcPaymentRequest struct {
5420
        *lnrpc.SendRequest
5421
        route *route.Route
5422
}
5423

5424
// SendPayment dispatches a bi-directional streaming RPC for sending payments
5425
// through the Lightning Network. A single RPC invocation creates a persistent
5426
// bi-directional stream allowing clients to rapidly send payments through the
5427
// Lightning Network with a single persistent connection.
5428
func (r *rpcServer) SendPayment(stream lnrpc.Lightning_SendPaymentServer) error {
×
5429
        var lock sync.Mutex
×
5430

×
5431
        return r.sendPayment(&paymentStream{
×
5432
                recv: func() (*rpcPaymentRequest, error) {
×
5433
                        req, err := stream.Recv()
×
5434
                        if err != nil {
×
5435
                                return nil, err
×
5436
                        }
×
5437

5438
                        return &rpcPaymentRequest{
×
5439
                                SendRequest: req,
×
5440
                        }, nil
×
5441
                },
5442
                send: func(r *lnrpc.SendResponse) error {
×
5443
                        // Calling stream.Send concurrently is not safe.
×
5444
                        lock.Lock()
×
5445
                        defer lock.Unlock()
×
5446
                        return stream.Send(r)
×
5447
                },
×
5448
        })
5449
}
5450

5451
// SendToRoute dispatches a bi-directional streaming RPC for sending payments
5452
// through the Lightning Network via predefined routes passed in. A single RPC
5453
// invocation creates a persistent bi-directional stream allowing clients to
5454
// rapidly send payments through the Lightning Network with a single persistent
5455
// connection.
5456
func (r *rpcServer) SendToRoute(stream lnrpc.Lightning_SendToRouteServer) error {
3✔
5457
        var lock sync.Mutex
3✔
5458

3✔
5459
        return r.sendPayment(&paymentStream{
3✔
5460
                recv: func() (*rpcPaymentRequest, error) {
6✔
5461
                        req, err := stream.Recv()
3✔
5462
                        if err != nil {
6✔
5463
                                return nil, err
3✔
5464
                        }
3✔
5465

5466
                        return r.unmarshallSendToRouteRequest(req)
3✔
5467
                },
5468
                send: func(r *lnrpc.SendResponse) error {
3✔
5469
                        // Calling stream.Send concurrently is not safe.
3✔
5470
                        lock.Lock()
3✔
5471
                        defer lock.Unlock()
3✔
5472
                        return stream.Send(r)
3✔
5473
                },
3✔
5474
        })
5475
}
5476

5477
// unmarshallSendToRouteRequest unmarshalls an rpc sendtoroute request
5478
func (r *rpcServer) unmarshallSendToRouteRequest(
5479
        req *lnrpc.SendToRouteRequest) (*rpcPaymentRequest, error) {
3✔
5480

3✔
5481
        if req.Route == nil {
3✔
5482
                return nil, fmt.Errorf("unable to send, no route provided")
×
5483
        }
×
5484

5485
        route, err := r.routerBackend.UnmarshallRoute(req.Route)
3✔
5486
        if err != nil {
3✔
5487
                return nil, err
×
5488
        }
×
5489

5490
        return &rpcPaymentRequest{
3✔
5491
                SendRequest: &lnrpc.SendRequest{
3✔
5492
                        PaymentHash:       req.PaymentHash,
3✔
5493
                        PaymentHashString: req.PaymentHashString,
3✔
5494
                },
3✔
5495
                route: route,
3✔
5496
        }, nil
3✔
5497
}
5498

5499
// rpcPaymentIntent is a small wrapper struct around the of values we can
5500
// receive from a client over RPC if they wish to send a payment. We'll either
5501
// extract these fields from a payment request (which may include routing
5502
// hints), or we'll get a fully populated route from the user that we'll pass
5503
// directly to the channel router for dispatching.
5504
type rpcPaymentIntent struct {
5505
        msat               lnwire.MilliSatoshi
5506
        feeLimit           lnwire.MilliSatoshi
5507
        cltvLimit          uint32
5508
        dest               route.Vertex
5509
        rHash              [32]byte
5510
        cltvDelta          uint16
5511
        routeHints         [][]zpay32.HopHint
5512
        outgoingChannelIDs []uint64
5513
        lastHop            *route.Vertex
5514
        destFeatures       *lnwire.FeatureVector
5515
        paymentAddr        fn.Option[[32]byte]
5516
        payReq             []byte
5517
        metadata           []byte
5518
        blindedPathSet     *routing.BlindedPaymentPathSet
5519

5520
        destCustomRecords record.CustomSet
5521

5522
        route *route.Route
5523
}
5524

5525
// extractPaymentIntent attempts to parse the complete details required to
5526
// dispatch a client from the information presented by an RPC client. There are
5527
// three ways a client can specify their payment details: a payment request,
5528
// via manual details, or via a complete route.
5529
func (r *rpcServer) extractPaymentIntent(rpcPayReq *rpcPaymentRequest) (rpcPaymentIntent, error) {
3✔
5530
        payIntent := rpcPaymentIntent{}
3✔
5531

3✔
5532
        // If a route was specified, then we can use that directly.
3✔
5533
        if rpcPayReq.route != nil {
6✔
5534
                // If the user is using the REST interface, then they'll be
3✔
5535
                // passing the payment hash as a hex encoded string.
3✔
5536
                if rpcPayReq.PaymentHashString != "" {
3✔
5537
                        paymentHash, err := hex.DecodeString(
×
5538
                                rpcPayReq.PaymentHashString,
×
5539
                        )
×
5540
                        if err != nil {
×
5541
                                return payIntent, err
×
5542
                        }
×
5543

5544
                        copy(payIntent.rHash[:], paymentHash)
×
5545
                } else {
3✔
5546
                        copy(payIntent.rHash[:], rpcPayReq.PaymentHash)
3✔
5547
                }
3✔
5548

5549
                payIntent.route = rpcPayReq.route
3✔
5550
                return payIntent, nil
3✔
5551
        }
5552

5553
        // If there are no routes specified, pass along a outgoing channel
5554
        // restriction if specified. The main server rpc does not support
5555
        // multiple channel restrictions.
5556
        if rpcPayReq.OutgoingChanId != 0 {
×
5557
                payIntent.outgoingChannelIDs = []uint64{
×
5558
                        rpcPayReq.OutgoingChanId,
×
5559
                }
×
5560
        }
×
5561

5562
        // Pass along a last hop restriction if specified.
5563
        if len(rpcPayReq.LastHopPubkey) > 0 {
×
5564
                lastHop, err := route.NewVertexFromBytes(
×
5565
                        rpcPayReq.LastHopPubkey,
×
5566
                )
×
5567
                if err != nil {
×
5568
                        return payIntent, err
×
5569
                }
×
5570
                payIntent.lastHop = &lastHop
×
5571
        }
5572

5573
        // Take the CLTV limit from the request if set, otherwise use the max.
5574
        cltvLimit, err := routerrpc.ValidateCLTVLimit(
×
5575
                rpcPayReq.CltvLimit, r.cfg.MaxOutgoingCltvExpiry,
×
5576
        )
×
5577
        if err != nil {
×
5578
                return payIntent, err
×
5579
        }
×
5580
        payIntent.cltvLimit = cltvLimit
×
5581

×
5582
        customRecords := record.CustomSet(rpcPayReq.DestCustomRecords)
×
5583
        if err := customRecords.Validate(); err != nil {
×
5584
                return payIntent, err
×
5585
        }
×
5586
        payIntent.destCustomRecords = customRecords
×
5587

×
5588
        validateDest := func(dest route.Vertex) error {
×
5589
                if rpcPayReq.AllowSelfPayment {
×
5590
                        return nil
×
5591
                }
×
5592

5593
                if dest == r.selfNode {
×
5594
                        return errors.New("self-payments not allowed")
×
5595
                }
×
5596

5597
                return nil
×
5598
        }
5599

5600
        // If the payment request field isn't blank, then the details of the
5601
        // invoice are encoded entirely within the encoded payReq.  So we'll
5602
        // attempt to decode it, populating the payment accordingly.
5603
        if rpcPayReq.PaymentRequest != "" {
×
5604
                payReq, err := zpay32.Decode(
×
5605
                        rpcPayReq.PaymentRequest, r.cfg.ActiveNetParams.Params,
×
5606
                        zpay32.WithErrorOnUnknownFeatureBit(),
×
5607
                )
×
5608
                if err != nil {
×
5609
                        return payIntent, err
×
5610
                }
×
5611

5612
                // Next, we'll ensure that this payreq hasn't already expired.
5613
                err = routerrpc.ValidatePayReqExpiry(payReq)
×
5614
                if err != nil {
×
5615
                        return payIntent, err
×
5616
                }
×
5617

5618
                // If the amount was not included in the invoice, then we let
5619
                // the payer specify the amount of satoshis they wish to send.
5620
                // We override the amount to pay with the amount provided from
5621
                // the payment request.
5622
                if payReq.MilliSat == nil {
×
5623
                        amt, err := lnrpc.UnmarshallAmt(
×
5624
                                rpcPayReq.Amt, rpcPayReq.AmtMsat,
×
5625
                        )
×
5626
                        if err != nil {
×
5627
                                return payIntent, err
×
5628
                        }
×
5629
                        if amt == 0 {
×
5630
                                return payIntent, errors.New("amount must be " +
×
5631
                                        "specified when paying a zero amount " +
×
5632
                                        "invoice")
×
5633
                        }
×
5634

5635
                        payIntent.msat = amt
×
5636
                } else {
×
5637
                        payIntent.msat = *payReq.MilliSat
×
5638
                }
×
5639

5640
                // Calculate the fee limit that should be used for this payment.
5641
                payIntent.feeLimit = lnrpc.CalculateFeeLimit(
×
5642
                        rpcPayReq.FeeLimit, payIntent.msat,
×
5643
                )
×
5644

×
5645
                copy(payIntent.rHash[:], payReq.PaymentHash[:])
×
5646
                destKey := payReq.Destination.SerializeCompressed()
×
5647
                copy(payIntent.dest[:], destKey)
×
5648
                payIntent.cltvDelta = uint16(payReq.MinFinalCLTVExpiry())
×
5649
                payIntent.routeHints = payReq.RouteHints
×
5650
                payIntent.payReq = []byte(rpcPayReq.PaymentRequest)
×
5651
                payIntent.destFeatures = payReq.Features
×
5652
                payIntent.paymentAddr = payReq.PaymentAddr
×
5653
                payIntent.metadata = payReq.Metadata
×
5654

×
5655
                if len(payReq.BlindedPaymentPaths) > 0 {
×
5656
                        pathSet, err := routerrpc.BuildBlindedPathSet(
×
5657
                                payReq.BlindedPaymentPaths,
×
5658
                        )
×
5659
                        if err != nil {
×
5660
                                return payIntent, err
×
5661
                        }
×
5662
                        payIntent.blindedPathSet = pathSet
×
5663

×
5664
                        // Replace the destination node with the target public
×
5665
                        // key of the blinded path set.
×
5666
                        copy(
×
5667
                                payIntent.dest[:],
×
5668
                                pathSet.TargetPubKey().SerializeCompressed(),
×
5669
                        )
×
5670

×
5671
                        pathFeatures := pathSet.Features()
×
5672
                        if !pathFeatures.IsEmpty() {
×
5673
                                payIntent.destFeatures = pathFeatures.Clone()
×
5674
                        }
×
5675
                }
5676

5677
                if err := validateDest(payIntent.dest); err != nil {
×
5678
                        return payIntent, err
×
5679
                }
×
5680

5681
                // Do bounds checking with the block padding.
5682
                err = routing.ValidateCLTVLimit(
×
5683
                        payIntent.cltvLimit, payIntent.cltvDelta, true,
×
5684
                )
×
5685
                if err != nil {
×
5686
                        return payIntent, err
×
5687
                }
×
5688

5689
                return payIntent, nil
×
5690
        }
5691

5692
        // At this point, a destination MUST be specified, so we'll convert it
5693
        // into the proper representation now. The destination will either be
5694
        // encoded as raw bytes, or via a hex string.
5695
        var pubBytes []byte
×
5696
        if len(rpcPayReq.Dest) != 0 {
×
5697
                pubBytes = rpcPayReq.Dest
×
5698
        } else {
×
5699
                var err error
×
5700
                pubBytes, err = hex.DecodeString(rpcPayReq.DestString)
×
5701
                if err != nil {
×
5702
                        return payIntent, err
×
5703
                }
×
5704
        }
5705
        if len(pubBytes) != 33 {
×
5706
                return payIntent, errors.New("invalid key length")
×
5707
        }
×
5708
        copy(payIntent.dest[:], pubBytes)
×
5709

×
5710
        if err := validateDest(payIntent.dest); err != nil {
×
5711
                return payIntent, err
×
5712
        }
×
5713

5714
        // Payment address may not be needed by legacy invoices.
5715
        if len(rpcPayReq.PaymentAddr) != 0 && len(rpcPayReq.PaymentAddr) != 32 {
×
5716
                return payIntent, errors.New("invalid payment address length")
×
5717
        }
×
5718

5719
        // Set the payment address if it was explicitly defined with the
5720
        // rpcPaymentRequest.
5721
        // Note that the payment address for the payIntent should be nil if none
5722
        // was provided with the rpcPaymentRequest.
5723
        if len(rpcPayReq.PaymentAddr) != 0 {
×
5724
                var addr [32]byte
×
5725
                copy(addr[:], rpcPayReq.PaymentAddr)
×
5726
                payIntent.paymentAddr = fn.Some(addr)
×
5727
        }
×
5728

5729
        // Otherwise, If the payment request field was not specified
5730
        // (and a custom route wasn't specified), construct the payment
5731
        // from the other fields.
5732
        payIntent.msat, err = lnrpc.UnmarshallAmt(
×
5733
                rpcPayReq.Amt, rpcPayReq.AmtMsat,
×
5734
        )
×
5735
        if err != nil {
×
5736
                return payIntent, err
×
5737
        }
×
5738

5739
        // Calculate the fee limit that should be used for this payment.
5740
        payIntent.feeLimit = lnrpc.CalculateFeeLimit(
×
5741
                rpcPayReq.FeeLimit, payIntent.msat,
×
5742
        )
×
5743

×
5744
        if rpcPayReq.FinalCltvDelta != 0 {
×
5745
                payIntent.cltvDelta = uint16(rpcPayReq.FinalCltvDelta)
×
5746
        } else {
×
5747
                // If no final cltv delta is given, assume the default that we
×
5748
                // use when creating an invoice. We do not assume the default of
×
5749
                // 9 blocks that is defined in BOLT-11, because this is never
×
5750
                // enough for other lnd nodes.
×
5751
                payIntent.cltvDelta = uint16(r.cfg.Bitcoin.TimeLockDelta)
×
5752
        }
×
5753

5754
        // Do bounds checking with the block padding so the router isn't left
5755
        // with a zombie payment in case the user messes up.
5756
        err = routing.ValidateCLTVLimit(
×
5757
                payIntent.cltvLimit, payIntent.cltvDelta, true,
×
5758
        )
×
5759
        if err != nil {
×
5760
                return payIntent, err
×
5761
        }
×
5762

5763
        // If the user is manually specifying payment details, then the payment
5764
        // hash may be encoded as a string.
5765
        switch {
×
5766
        case rpcPayReq.PaymentHashString != "":
×
5767
                paymentHash, err := hex.DecodeString(
×
5768
                        rpcPayReq.PaymentHashString,
×
5769
                )
×
5770
                if err != nil {
×
5771
                        return payIntent, err
×
5772
                }
×
5773

5774
                copy(payIntent.rHash[:], paymentHash)
×
5775

5776
        default:
×
5777
                copy(payIntent.rHash[:], rpcPayReq.PaymentHash)
×
5778
        }
5779

5780
        // Unmarshal any custom destination features.
5781
        payIntent.destFeatures, err = routerrpc.UnmarshalFeatures(
×
5782
                rpcPayReq.DestFeatures,
×
5783
        )
×
5784
        if err != nil {
×
5785
                return payIntent, err
×
5786
        }
×
5787

5788
        return payIntent, nil
×
5789
}
5790

5791
type paymentIntentResponse struct {
5792
        Route    *route.Route
5793
        Preimage [32]byte
5794
        Err      error
5795
}
5796

5797
// dispatchPaymentIntent attempts to fully dispatch an RPC payment intent.
5798
// We'll either pass the payment as a whole to the channel router, or give it a
5799
// pre-built route. The first error this method returns denotes if we were
5800
// unable to save the payment. The second error returned denotes if the payment
5801
// didn't succeed.
5802
func (r *rpcServer) dispatchPaymentIntent(
5803
        payIntent *rpcPaymentIntent) (*paymentIntentResponse, error) {
3✔
5804

3✔
5805
        // Construct a payment request to send to the channel router. If the
3✔
5806
        // payment is successful, the route chosen will be returned. Otherwise,
3✔
5807
        // we'll get a non-nil error.
3✔
5808
        var (
3✔
5809
                preImage  [32]byte
3✔
5810
                route     *route.Route
3✔
5811
                routerErr error
3✔
5812
        )
3✔
5813

3✔
5814
        // If a route was specified, then we'll pass the route directly to the
3✔
5815
        // router, otherwise we'll create a payment session to execute it.
3✔
5816
        if payIntent.route == nil {
3✔
5817
                payment := &routing.LightningPayment{
×
5818
                        Target:             payIntent.dest,
×
5819
                        Amount:             payIntent.msat,
×
5820
                        FinalCLTVDelta:     payIntent.cltvDelta,
×
5821
                        FeeLimit:           payIntent.feeLimit,
×
5822
                        CltvLimit:          payIntent.cltvLimit,
×
5823
                        RouteHints:         payIntent.routeHints,
×
5824
                        OutgoingChannelIDs: payIntent.outgoingChannelIDs,
×
5825
                        LastHop:            payIntent.lastHop,
×
5826
                        PaymentRequest:     payIntent.payReq,
×
5827
                        PayAttemptTimeout:  routing.DefaultPayAttemptTimeout,
×
5828
                        DestCustomRecords:  payIntent.destCustomRecords,
×
5829
                        DestFeatures:       payIntent.destFeatures,
×
5830
                        PaymentAddr:        payIntent.paymentAddr,
×
5831
                        Metadata:           payIntent.metadata,
×
5832
                        BlindedPathSet:     payIntent.blindedPathSet,
×
5833

×
5834
                        // Don't enable multi-part payments on the main rpc.
×
5835
                        // Users need to use routerrpc for that.
×
5836
                        MaxParts: 1,
×
5837
                }
×
5838
                err := payment.SetPaymentHash(payIntent.rHash)
×
5839
                if err != nil {
×
5840
                        return nil, err
×
5841
                }
×
5842

5843
                preImage, route, routerErr = r.server.chanRouter.SendPayment(
×
5844
                        payment,
×
5845
                )
×
5846
        } else {
3✔
5847
                var attempt *channeldb.HTLCAttempt
3✔
5848
                attempt, routerErr = r.server.chanRouter.SendToRoute(
3✔
5849
                        payIntent.rHash, payIntent.route, nil,
3✔
5850
                )
3✔
5851

3✔
5852
                if routerErr == nil {
6✔
5853
                        preImage = attempt.Settle.Preimage
3✔
5854
                }
3✔
5855

5856
                route = payIntent.route
3✔
5857
        }
5858

5859
        // If the route failed, then we'll return a nil save err, but a non-nil
5860
        // routing err.
5861
        if routerErr != nil {
6✔
5862
                rpcsLog.Warnf("Unable to send payment: %v", routerErr)
3✔
5863

3✔
5864
                return &paymentIntentResponse{
3✔
5865
                        Err: routerErr,
3✔
5866
                }, nil
3✔
5867
        }
3✔
5868

5869
        return &paymentIntentResponse{
3✔
5870
                Route:    route,
3✔
5871
                Preimage: preImage,
3✔
5872
        }, nil
3✔
5873
}
5874

5875
// sendPayment takes a paymentStream (a source of pre-built routes or payment
5876
// requests) and continually attempt to dispatch payment requests written to
5877
// the write end of the stream. Responses will also be streamed back to the
5878
// client via the write end of the stream. This method is by both SendToRoute
5879
// and SendPayment as the logic is virtually identical.
5880
func (r *rpcServer) sendPayment(stream *paymentStream) error {
3✔
5881
        payChan := make(chan *rpcPaymentIntent)
3✔
5882
        errChan := make(chan error, 1)
3✔
5883

3✔
5884
        // We don't allow payments to be sent while the daemon itself is still
3✔
5885
        // syncing as we may be trying to sent a payment over a "stale"
3✔
5886
        // channel.
3✔
5887
        if !r.server.Started() {
3✔
5888
                return ErrServerNotActive
×
5889
        }
×
5890

5891
        // TODO(roasbeef): check payment filter to see if already used?
5892

5893
        // In order to limit the level of concurrency and prevent a client from
5894
        // attempting to OOM the server, we'll set up a semaphore to create an
5895
        // upper ceiling on the number of outstanding payments.
5896
        const numOutstandingPayments = 2000
3✔
5897
        htlcSema := make(chan struct{}, numOutstandingPayments)
3✔
5898
        for i := 0; i < numOutstandingPayments; i++ {
6✔
5899
                htlcSema <- struct{}{}
3✔
5900
        }
3✔
5901

5902
        // We keep track of the running goroutines and set up a quit signal we
5903
        // can use to request them to exit if the method returns because of an
5904
        // encountered error.
5905
        var wg sync.WaitGroup
3✔
5906
        reqQuit := make(chan struct{})
3✔
5907
        defer close(reqQuit)
3✔
5908

3✔
5909
        // Launch a new goroutine to handle reading new payment requests from
3✔
5910
        // the client. This way we can handle errors independently of blocking
3✔
5911
        // and waiting for the next payment request to come through.
3✔
5912
        // TODO(joostjager): Callers expect result to come in in the same order
3✔
5913
        // as the request were sent, but this is far from guarantueed in the
3✔
5914
        // code below.
3✔
5915
        wg.Add(1)
3✔
5916
        go func() {
6✔
5917
                defer wg.Done()
3✔
5918

3✔
5919
                for {
6✔
5920
                        select {
3✔
5921
                        case <-reqQuit:
×
5922
                                return
×
5923

5924
                        default:
3✔
5925
                                // Receive the next pending payment within the
3✔
5926
                                // stream sent by the client. If we read the
3✔
5927
                                // EOF sentinel, then the client has closed the
3✔
5928
                                // stream, and we can exit normally.
3✔
5929
                                nextPayment, err := stream.recv()
3✔
5930
                                if err == io.EOF {
3✔
5931
                                        close(payChan)
×
5932
                                        return
×
5933
                                } else if err != nil {
6✔
5934
                                        rpcsLog.Errorf("Failed receiving from "+
3✔
5935
                                                "stream: %v", err)
3✔
5936

3✔
5937
                                        select {
3✔
5938
                                        case errChan <- err:
3✔
5939
                                        default:
×
5940
                                        }
5941
                                        return
3✔
5942
                                }
5943

5944
                                // Populate the next payment, either from the
5945
                                // payment request, or from the explicitly set
5946
                                // fields. If the payment proto wasn't well
5947
                                // formed, then we'll send an error reply and
5948
                                // wait for the next payment.
5949
                                payIntent, err := r.extractPaymentIntent(
3✔
5950
                                        nextPayment,
3✔
5951
                                )
3✔
5952
                                if err != nil {
3✔
5953
                                        if err := stream.send(&lnrpc.SendResponse{
×
5954
                                                PaymentError: err.Error(),
×
5955
                                                PaymentHash:  payIntent.rHash[:],
×
5956
                                        }); err != nil {
×
5957
                                                rpcsLog.Errorf("Failed "+
×
5958
                                                        "sending on "+
×
5959
                                                        "stream: %v", err)
×
5960

×
5961
                                                select {
×
5962
                                                case errChan <- err:
×
5963
                                                default:
×
5964
                                                }
5965
                                                return
×
5966
                                        }
5967
                                        continue
×
5968
                                }
5969

5970
                                // If the payment was well formed, then we'll
5971
                                // send to the dispatch goroutine, or exit,
5972
                                // which ever comes first.
5973
                                select {
3✔
5974
                                case payChan <- &payIntent:
3✔
5975
                                case <-reqQuit:
×
5976
                                        return
×
5977
                                }
5978
                        }
5979
                }
5980
        }()
5981

5982
sendLoop:
3✔
5983
        for {
6✔
5984
                select {
3✔
5985

5986
                // If we encounter and error either during sending or
5987
                // receiving, we return directly, closing the stream.
5988
                case err := <-errChan:
3✔
5989
                        return err
3✔
5990

5991
                case <-r.quit:
×
5992
                        return errors.New("rpc server shutting down")
×
5993

5994
                case payIntent, ok := <-payChan:
3✔
5995
                        // If the receive loop is done, we break the send loop
3✔
5996
                        // and wait for the ongoing payments to finish before
3✔
5997
                        // exiting.
3✔
5998
                        if !ok {
3✔
5999
                                break sendLoop
×
6000
                        }
6001

6002
                        // We launch a new goroutine to execute the current
6003
                        // payment so we can continue to serve requests while
6004
                        // this payment is being dispatched.
6005
                        wg.Add(1)
3✔
6006
                        go func(payIntent *rpcPaymentIntent) {
6✔
6007
                                defer wg.Done()
3✔
6008

3✔
6009
                                // Attempt to grab a free semaphore slot, using
3✔
6010
                                // a defer to eventually release the slot
3✔
6011
                                // regardless of payment success.
3✔
6012
                                select {
3✔
6013
                                case <-htlcSema:
3✔
6014
                                case <-reqQuit:
×
6015
                                        return
×
6016
                                }
6017
                                defer func() {
6✔
6018
                                        htlcSema <- struct{}{}
3✔
6019
                                }()
3✔
6020

6021
                                resp, saveErr := r.dispatchPaymentIntent(
3✔
6022
                                        payIntent,
3✔
6023
                                )
3✔
6024

3✔
6025
                                switch {
3✔
6026
                                // If we were unable to save the state of the
6027
                                // payment, then we'll return the error to the
6028
                                // user, and terminate.
6029
                                case saveErr != nil:
×
6030
                                        rpcsLog.Errorf("Failed dispatching "+
×
6031
                                                "payment intent: %v", saveErr)
×
6032

×
6033
                                        select {
×
6034
                                        case errChan <- saveErr:
×
6035
                                        default:
×
6036
                                        }
6037
                                        return
×
6038

6039
                                // If we receive payment error than, instead of
6040
                                // terminating the stream, send error response
6041
                                // to the user.
6042
                                case resp.Err != nil:
3✔
6043
                                        err := stream.send(&lnrpc.SendResponse{
3✔
6044
                                                PaymentError: resp.Err.Error(),
3✔
6045
                                                PaymentHash:  payIntent.rHash[:],
3✔
6046
                                        })
3✔
6047
                                        if err != nil {
3✔
6048
                                                rpcsLog.Errorf("Failed "+
×
6049
                                                        "sending error "+
×
6050
                                                        "response: %v", err)
×
6051

×
6052
                                                select {
×
6053
                                                case errChan <- err:
×
6054
                                                default:
×
6055
                                                }
6056
                                        }
6057
                                        return
3✔
6058
                                }
6059

6060
                                backend := r.routerBackend
3✔
6061
                                marshalledRouted, err := backend.MarshallRoute(
3✔
6062
                                        resp.Route,
3✔
6063
                                )
3✔
6064
                                if err != nil {
3✔
6065
                                        errChan <- err
×
6066
                                        return
×
6067
                                }
×
6068

6069
                                err = stream.send(&lnrpc.SendResponse{
3✔
6070
                                        PaymentHash:     payIntent.rHash[:],
3✔
6071
                                        PaymentPreimage: resp.Preimage[:],
3✔
6072
                                        PaymentRoute:    marshalledRouted,
3✔
6073
                                })
3✔
6074
                                if err != nil {
3✔
6075
                                        rpcsLog.Errorf("Failed sending "+
×
6076
                                                "response: %v", err)
×
6077

×
6078
                                        select {
×
6079
                                        case errChan <- err:
×
6080
                                        default:
×
6081
                                        }
6082
                                        return
×
6083
                                }
6084
                        }(payIntent)
6085
                }
6086
        }
6087

6088
        // Wait for all goroutines to finish before closing the stream.
6089
        wg.Wait()
×
6090
        return nil
×
6091
}
6092

6093
// SendPaymentSync is the synchronous non-streaming version of SendPayment.
6094
// This RPC is intended to be consumed by clients of the REST proxy.
6095
// Additionally, this RPC expects the destination's public key and the payment
6096
// hash (if any) to be encoded as hex strings.
6097
func (r *rpcServer) SendPaymentSync(ctx context.Context,
6098
        nextPayment *lnrpc.SendRequest) (*lnrpc.SendResponse, error) {
×
6099

×
6100
        return r.sendPaymentSync(&rpcPaymentRequest{
×
6101
                SendRequest: nextPayment,
×
6102
        })
×
6103
}
×
6104

6105
// SendToRouteSync is the synchronous non-streaming version of SendToRoute.
6106
// This RPC is intended to be consumed by clients of the REST proxy.
6107
// Additionally, this RPC expects the payment hash (if any) to be encoded as
6108
// hex strings.
6109
func (r *rpcServer) SendToRouteSync(ctx context.Context,
6110
        req *lnrpc.SendToRouteRequest) (*lnrpc.SendResponse, error) {
3✔
6111

3✔
6112
        if req.Route == nil {
3✔
6113
                return nil, fmt.Errorf("unable to send, no routes provided")
×
6114
        }
×
6115

6116
        paymentRequest, err := r.unmarshallSendToRouteRequest(req)
3✔
6117
        if err != nil {
3✔
6118
                return nil, err
×
6119
        }
×
6120

6121
        return r.sendPaymentSync(paymentRequest)
3✔
6122
}
6123

6124
// sendPaymentSync is the synchronous variant of sendPayment. It will block and
6125
// wait until the payment has been fully completed.
6126
func (r *rpcServer) sendPaymentSync(
6127
        nextPayment *rpcPaymentRequest) (*lnrpc.SendResponse, error) {
3✔
6128

3✔
6129
        // We don't allow payments to be sent while the daemon itself is still
3✔
6130
        // syncing as we may be trying to sent a payment over a "stale"
3✔
6131
        // channel.
3✔
6132
        if !r.server.Started() {
3✔
6133
                return nil, ErrServerNotActive
×
6134
        }
×
6135

6136
        // First we'll attempt to map the proto describing the next payment to
6137
        // an intent that we can pass to local sub-systems.
6138
        payIntent, err := r.extractPaymentIntent(nextPayment)
3✔
6139
        if err != nil {
3✔
6140
                return nil, err
×
6141
        }
×
6142

6143
        // With the payment validated, we'll now attempt to dispatch the
6144
        // payment.
6145
        resp, saveErr := r.dispatchPaymentIntent(&payIntent)
3✔
6146
        switch {
3✔
6147
        case saveErr != nil:
×
6148
                return nil, saveErr
×
6149

6150
        case resp.Err != nil:
×
6151
                return &lnrpc.SendResponse{
×
6152
                        PaymentError: resp.Err.Error(),
×
6153
                        PaymentHash:  payIntent.rHash[:],
×
6154
                }, nil
×
6155
        }
6156

6157
        rpcRoute, err := r.routerBackend.MarshallRoute(resp.Route)
3✔
6158
        if err != nil {
3✔
6159
                return nil, err
×
6160
        }
×
6161

6162
        return &lnrpc.SendResponse{
3✔
6163
                PaymentHash:     payIntent.rHash[:],
3✔
6164
                PaymentPreimage: resp.Preimage[:],
3✔
6165
                PaymentRoute:    rpcRoute,
3✔
6166
        }, nil
3✔
6167
}
6168

6169
// AddInvoice attempts to add a new invoice to the invoice database. Any
6170
// duplicated invoices are rejected, therefore all invoices *must* have a
6171
// unique payment preimage.
6172
func (r *rpcServer) AddInvoice(ctx context.Context,
6173
        invoice *lnrpc.Invoice) (*lnrpc.AddInvoiceResponse, error) {
3✔
6174

3✔
6175
        var (
3✔
6176
                defaultDelta = r.cfg.Bitcoin.TimeLockDelta
3✔
6177
                blindCfg     = invoice.BlindedPathConfig
3✔
6178
                blind        = invoice.IsBlinded
3✔
6179
        )
3✔
6180

3✔
6181
        globalBlindCfg := r.server.cfg.Routing.BlindedPaths
3✔
6182
        blindingRestrictions := &routing.BlindedPathRestrictions{
3✔
6183
                MinDistanceFromIntroNode: globalBlindCfg.MinNumRealHops,
3✔
6184
                NumHops:                  globalBlindCfg.NumHops,
3✔
6185
                MaxNumPaths:              globalBlindCfg.MaxNumPaths,
3✔
6186
                NodeOmissionSet:          fn.NewSet[route.Vertex](),
3✔
6187
        }
3✔
6188

3✔
6189
        if blindCfg != nil && !blind {
3✔
6190
                return nil, fmt.Errorf("blinded path config provided but " +
×
6191
                        "IsBlinded not set")
×
6192
        }
×
6193

6194
        if blind && blindCfg != nil {
6✔
6195
                if blindCfg.MinNumRealHops != nil {
6✔
6196
                        blindingRestrictions.MinDistanceFromIntroNode =
3✔
6197
                                uint8(*blindCfg.MinNumRealHops)
3✔
6198
                }
3✔
6199
                if blindCfg.NumHops != nil {
6✔
6200
                        blindingRestrictions.NumHops = uint8(*blindCfg.NumHops)
3✔
6201
                }
3✔
6202
                if blindCfg.MaxNumPaths != nil {
3✔
6203
                        blindingRestrictions.MaxNumPaths =
×
6204
                                uint8(*blindCfg.MaxNumPaths)
×
6205
                }
×
6206

6207
                for _, nodeIDBytes := range blindCfg.NodeOmissionList {
3✔
6208
                        vertex, err := route.NewVertexFromBytes(nodeIDBytes)
×
6209
                        if err != nil {
×
6210
                                return nil, err
×
6211
                        }
×
6212

6213
                        blindingRestrictions.NodeOmissionSet.Add(vertex)
×
6214
                }
6215
        }
6216

6217
        if blindingRestrictions.MinDistanceFromIntroNode >
3✔
6218
                blindingRestrictions.NumHops {
3✔
6219

×
6220
                return nil, fmt.Errorf("the minimum number of real " +
×
6221
                        "hops in a blinded path must be smaller than " +
×
6222
                        "or equal to the number of hops expected to " +
×
6223
                        "be included in each path")
×
6224
        }
×
6225

6226
        addInvoiceCfg := &invoicesrpc.AddInvoiceConfig{
3✔
6227
                AddInvoice:        r.server.invoices.AddInvoice,
3✔
6228
                IsChannelActive:   r.server.htlcSwitch.HasActiveLink,
3✔
6229
                ChainParams:       r.cfg.ActiveNetParams.Params,
3✔
6230
                NodeSigner:        r.server.nodeSigner,
3✔
6231
                DefaultCLTVExpiry: defaultDelta,
3✔
6232
                ChanDB:            r.server.chanStateDB,
3✔
6233
                Graph:             r.server.graphDB,
3✔
6234
                GenInvoiceFeatures: func() *lnwire.FeatureVector {
6✔
6235
                        v := r.server.featureMgr.Get(feature.SetInvoice)
3✔
6236

3✔
6237
                        if blind {
6✔
6238
                                // If an invoice includes blinded paths, then a
3✔
6239
                                // payment address is not required since we use
3✔
6240
                                // the PathID in the final hop's encrypted data
3✔
6241
                                // as equivalent to the payment address
3✔
6242
                                v.Unset(lnwire.PaymentAddrRequired)
3✔
6243
                                v.Set(lnwire.PaymentAddrOptional)
3✔
6244

3✔
6245
                                // The invoice payer will also need to
3✔
6246
                                // understand the new BOLT 11 tagged field
3✔
6247
                                // containing the blinded path, so we switch
3✔
6248
                                // the bit to required.
3✔
6249
                                v = feature.SetBit(
3✔
6250
                                        v, lnwire.Bolt11BlindedPathsRequired,
3✔
6251
                                )
3✔
6252
                        }
3✔
6253

6254
                        return v
3✔
6255
                },
6256
                GenAmpInvoiceFeatures: func() *lnwire.FeatureVector {
3✔
6257
                        return r.server.featureMgr.Get(feature.SetInvoiceAmp)
3✔
6258
                },
3✔
6259
                GetAlias:   r.server.aliasMgr.GetPeerAlias,
6260
                BestHeight: r.server.cc.BestBlockTracker.BestHeight,
6261
                QueryBlindedRoutes: func(amt lnwire.MilliSatoshi) (
6262
                        []*route.Route, error) {
3✔
6263

3✔
6264
                        return r.server.chanRouter.FindBlindedPaths(
3✔
6265
                                r.selfNode, amt,
3✔
6266
                                r.server.defaultMC.GetProbability,
3✔
6267
                                blindingRestrictions,
3✔
6268
                        )
3✔
6269
                },
3✔
6270
        }
6271

6272
        value, err := lnrpc.UnmarshallAmt(invoice.Value, invoice.ValueMsat)
3✔
6273
        if err != nil {
3✔
6274
                return nil, err
×
6275
        }
×
6276

6277
        // Convert the passed routing hints to the required format.
6278
        routeHints, err := invoicesrpc.CreateZpay32HopHints(invoice.RouteHints)
3✔
6279
        if err != nil {
3✔
6280
                return nil, err
×
6281
        }
×
6282

6283
        var blindedPathCfg *invoicesrpc.BlindedPathConfig
3✔
6284
        if blind {
6✔
6285
                bpConfig := r.server.cfg.Routing.BlindedPaths
3✔
6286

3✔
6287
                blindedPathCfg = &invoicesrpc.BlindedPathConfig{
3✔
6288
                        RoutePolicyIncrMultiplier: bpConfig.
3✔
6289
                                PolicyIncreaseMultiplier,
3✔
6290
                        RoutePolicyDecrMultiplier: bpConfig.
3✔
6291
                                PolicyDecreaseMultiplier,
3✔
6292
                        DefaultDummyHopPolicy: &blindedpath.BlindedHopPolicy{
3✔
6293
                                CLTVExpiryDelta: uint16(defaultDelta),
3✔
6294
                                FeeRate: uint32(
3✔
6295
                                        r.server.cfg.Bitcoin.FeeRate,
3✔
6296
                                ),
3✔
6297
                                BaseFee:     r.server.cfg.Bitcoin.BaseFee,
3✔
6298
                                MinHTLCMsat: r.server.cfg.Bitcoin.MinHTLCIn,
3✔
6299

3✔
6300
                                // MaxHTLCMsat will be calculated on the fly by
3✔
6301
                                // using the introduction node's channel's
3✔
6302
                                // capacities.
3✔
6303
                                MaxHTLCMsat: 0,
3✔
6304
                        },
3✔
6305
                        MinNumPathHops: blindingRestrictions.NumHops,
3✔
6306
                }
3✔
6307
        }
3✔
6308

6309
        addInvoiceData := &invoicesrpc.AddInvoiceData{
3✔
6310
                Memo:            invoice.Memo,
3✔
6311
                Value:           value,
3✔
6312
                DescriptionHash: invoice.DescriptionHash,
3✔
6313
                Expiry:          invoice.Expiry,
3✔
6314
                FallbackAddr:    invoice.FallbackAddr,
3✔
6315
                CltvExpiry:      invoice.CltvExpiry,
3✔
6316
                Private:         invoice.Private,
3✔
6317
                RouteHints:      routeHints,
3✔
6318
                Amp:             invoice.IsAmp,
3✔
6319
                BlindedPathCfg:  blindedPathCfg,
3✔
6320
        }
3✔
6321

3✔
6322
        if invoice.RPreimage != nil {
6✔
6323
                preimage, err := lntypes.MakePreimage(invoice.RPreimage)
3✔
6324
                if err != nil {
3✔
6325
                        return nil, err
×
6326
                }
×
6327
                addInvoiceData.Preimage = &preimage
3✔
6328
        }
6329

6330
        hash, dbInvoice, err := invoicesrpc.AddInvoice(
3✔
6331
                ctx, addInvoiceCfg, addInvoiceData,
3✔
6332
        )
3✔
6333
        if err != nil {
3✔
6334
                return nil, err
×
6335
        }
×
6336

6337
        return &lnrpc.AddInvoiceResponse{
3✔
6338
                AddIndex:       dbInvoice.AddIndex,
3✔
6339
                PaymentRequest: string(dbInvoice.PaymentRequest),
3✔
6340
                RHash:          hash[:],
3✔
6341
                PaymentAddr:    dbInvoice.Terms.PaymentAddr[:],
3✔
6342
        }, nil
3✔
6343
}
6344

6345
// LookupInvoice attempts to look up an invoice according to its payment hash.
6346
// The passed payment hash *must* be exactly 32 bytes, if not an error is
6347
// returned.
6348
func (r *rpcServer) LookupInvoice(ctx context.Context,
6349
        req *lnrpc.PaymentHash) (*lnrpc.Invoice, error) {
3✔
6350

3✔
6351
        var (
3✔
6352
                payHash [32]byte
3✔
6353
                rHash   []byte
3✔
6354
                err     error
3✔
6355
        )
3✔
6356

3✔
6357
        // If the RHash as a raw string was provided, then decode that and use
3✔
6358
        // that directly. Otherwise, we use the raw bytes provided.
3✔
6359
        if req.RHashStr != "" {
6✔
6360
                rHash, err = hex.DecodeString(req.RHashStr)
3✔
6361
                if err != nil {
3✔
6362
                        return nil, err
×
6363
                }
×
6364
        } else {
3✔
6365
                rHash = req.RHash
3✔
6366
        }
3✔
6367

6368
        // Ensure that the payment hash is *exactly* 32-bytes.
6369
        if len(rHash) != 0 && len(rHash) != 32 {
3✔
6370
                return nil, fmt.Errorf("payment hash must be exactly "+
×
6371
                        "32 bytes, is instead %v", len(rHash))
×
6372
        }
×
6373
        copy(payHash[:], rHash)
3✔
6374

3✔
6375
        rpcsLog.Tracef("[lookupinvoice] searching for invoice %x", payHash[:])
3✔
6376

3✔
6377
        invoice, err := r.server.invoices.LookupInvoice(ctx, payHash)
3✔
6378
        switch {
3✔
6379
        case errors.Is(err, invoices.ErrInvoiceNotFound):
×
6380
                return nil, status.Error(codes.NotFound, err.Error())
×
6381
        case err != nil:
×
6382
                return nil, err
×
6383
        }
6384

6385
        rpcsLog.Tracef("[lookupinvoice] located invoice %v",
3✔
6386
                lnutils.SpewLogClosure(invoice))
3✔
6387

3✔
6388
        rpcInvoice, err := invoicesrpc.CreateRPCInvoice(
3✔
6389
                &invoice, r.cfg.ActiveNetParams.Params,
3✔
6390
        )
3✔
6391
        if err != nil {
3✔
6392
                return nil, err
×
6393
        }
×
6394

6395
        // Give the aux data parser a chance to format the custom data in the
6396
        // invoice HTLCs.
6397
        err = fn.MapOptionZ(
3✔
6398
                r.server.implCfg.AuxDataParser,
3✔
6399
                func(parser AuxDataParser) error {
3✔
6400
                        return parser.InlineParseCustomData(rpcInvoice)
×
6401
                },
×
6402
        )
6403
        if err != nil {
3✔
6404
                return nil, fmt.Errorf("error parsing custom data: %w",
×
6405
                        err)
×
6406
        }
×
6407

6408
        return rpcInvoice, nil
3✔
6409
}
6410

6411
// ListInvoices returns a list of all the invoices currently stored within the
6412
// database. Any active debug invoices are ignored.
6413
func (r *rpcServer) ListInvoices(ctx context.Context,
6414
        req *lnrpc.ListInvoiceRequest) (*lnrpc.ListInvoiceResponse, error) {
3✔
6415

3✔
6416
        // If the number of invoices was not specified, then we'll default to
3✔
6417
        // returning the latest 100 invoices.
3✔
6418
        if req.NumMaxInvoices == 0 {
6✔
6419
                req.NumMaxInvoices = 100
3✔
6420
        }
3✔
6421

6422
        // If both dates are set, we check that the start date is less than the
6423
        // end date, otherwise we'll get an empty result.
6424
        if req.CreationDateStart != 0 && req.CreationDateEnd != 0 {
3✔
6425
                if req.CreationDateStart >= req.CreationDateEnd {
×
6426
                        return nil, fmt.Errorf("start date(%v) must be before "+
×
6427
                                "end date(%v)", req.CreationDateStart,
×
6428
                                req.CreationDateEnd)
×
6429
                }
×
6430
        }
6431

6432
        // Next, we'll map the proto request into a format that is understood by
6433
        // the database.
6434
        q := invoices.InvoiceQuery{
3✔
6435
                IndexOffset:       req.IndexOffset,
3✔
6436
                NumMaxInvoices:    req.NumMaxInvoices,
3✔
6437
                PendingOnly:       req.PendingOnly,
3✔
6438
                Reversed:          req.Reversed,
3✔
6439
                CreationDateStart: int64(req.CreationDateStart),
3✔
6440
                CreationDateEnd:   int64(req.CreationDateEnd),
3✔
6441
        }
3✔
6442

3✔
6443
        invoiceSlice, err := r.server.invoicesDB.QueryInvoices(ctx, q)
3✔
6444
        if err != nil {
3✔
6445
                return nil, fmt.Errorf("unable to query invoices: %w", err)
×
6446
        }
×
6447

6448
        // Before returning the response, we'll need to convert each invoice
6449
        // into it's proto representation.
6450
        resp := &lnrpc.ListInvoiceResponse{
3✔
6451
                Invoices:         make([]*lnrpc.Invoice, len(invoiceSlice.Invoices)),
3✔
6452
                FirstIndexOffset: invoiceSlice.FirstIndexOffset,
3✔
6453
                LastIndexOffset:  invoiceSlice.LastIndexOffset,
3✔
6454
        }
3✔
6455
        for i, invoice := range invoiceSlice.Invoices {
6✔
6456
                invoice := invoice
3✔
6457
                resp.Invoices[i], err = invoicesrpc.CreateRPCInvoice(
3✔
6458
                        &invoice, r.cfg.ActiveNetParams.Params,
3✔
6459
                )
3✔
6460
                if err != nil {
3✔
6461
                        return nil, err
×
6462
                }
×
6463

6464
                // Give the aux data parser a chance to format the custom data
6465
                // in the invoice HTLCs.
6466
                err = fn.MapOptionZ(
3✔
6467
                        r.server.implCfg.AuxDataParser,
3✔
6468
                        func(parser AuxDataParser) error {
3✔
6469
                                return parser.InlineParseCustomData(
×
6470
                                        resp.Invoices[i],
×
6471
                                )
×
6472
                        },
×
6473
                )
6474
                if err != nil {
3✔
6475
                        return nil, fmt.Errorf("error parsing custom data: %w",
×
6476
                                err)
×
6477
                }
×
6478
        }
6479

6480
        return resp, nil
3✔
6481
}
6482

6483
// SubscribeInvoices returns a uni-directional stream (server -> client) for
6484
// notifying the client of newly added/settled invoices.
6485
func (r *rpcServer) SubscribeInvoices(req *lnrpc.InvoiceSubscription,
6486
        updateStream lnrpc.Lightning_SubscribeInvoicesServer) error {
3✔
6487

3✔
6488
        invoiceClient, err := r.server.invoices.SubscribeNotifications(
3✔
6489
                updateStream.Context(), req.AddIndex, req.SettleIndex,
3✔
6490
        )
3✔
6491
        if err != nil {
3✔
6492
                return err
×
6493
        }
×
6494
        defer invoiceClient.Cancel()
3✔
6495

3✔
6496
        for {
6✔
6497
                select {
3✔
6498
                case newInvoice := <-invoiceClient.NewInvoices:
3✔
6499
                        rpcInvoice, err := invoicesrpc.CreateRPCInvoice(
3✔
6500
                                newInvoice, r.cfg.ActiveNetParams.Params,
3✔
6501
                        )
3✔
6502
                        if err != nil {
3✔
6503
                                return err
×
6504
                        }
×
6505

6506
                        // Give the aux data parser a chance to format the
6507
                        // custom data in the invoice HTLCs.
6508
                        err = fn.MapOptionZ(
3✔
6509
                                r.server.implCfg.AuxDataParser,
3✔
6510
                                func(parser AuxDataParser) error {
3✔
6511
                                        return parser.InlineParseCustomData(
×
6512
                                                rpcInvoice,
×
6513
                                        )
×
6514
                                },
×
6515
                        )
6516
                        if err != nil {
3✔
6517
                                return fmt.Errorf("error parsing custom data: "+
×
6518
                                        "%w", err)
×
6519
                        }
×
6520

6521
                        if err := updateStream.Send(rpcInvoice); err != nil {
3✔
6522
                                return err
×
6523
                        }
×
6524

6525
                case settledInvoice := <-invoiceClient.SettledInvoices:
3✔
6526
                        rpcInvoice, err := invoicesrpc.CreateRPCInvoice(
3✔
6527
                                settledInvoice, r.cfg.ActiveNetParams.Params,
3✔
6528
                        )
3✔
6529
                        if err != nil {
3✔
6530
                                return err
×
6531
                        }
×
6532

6533
                        // Give the aux data parser a chance to format the
6534
                        // custom data in the invoice HTLCs.
6535
                        err = fn.MapOptionZ(
3✔
6536
                                r.server.implCfg.AuxDataParser,
3✔
6537
                                func(parser AuxDataParser) error {
3✔
6538
                                        return parser.InlineParseCustomData(
×
6539
                                                rpcInvoice,
×
6540
                                        )
×
6541
                                },
×
6542
                        )
6543
                        if err != nil {
3✔
6544
                                return fmt.Errorf("error parsing custom data: "+
×
6545
                                        "%w", err)
×
6546
                        }
×
6547

6548
                        if err := updateStream.Send(rpcInvoice); err != nil {
3✔
6549
                                return err
×
6550
                        }
×
6551

6552
                // The response stream's context for whatever reason has been
6553
                // closed. If context is closed by an exceeded deadline we will
6554
                // return an error.
6555
                case <-updateStream.Context().Done():
3✔
6556
                        if errors.Is(updateStream.Context().Err(), context.Canceled) {
6✔
6557
                                return nil
3✔
6558
                        }
3✔
6559
                        return updateStream.Context().Err()
×
6560

6561
                case <-r.quit:
×
6562
                        return nil
×
6563
                }
6564
        }
6565
}
6566

6567
// SubscribeTransactions creates a uni-directional stream (server -> client) in
6568
// which any newly discovered transactions relevant to the wallet are sent
6569
// over.
6570
func (r *rpcServer) SubscribeTransactions(req *lnrpc.GetTransactionsRequest,
6571
        updateStream lnrpc.Lightning_SubscribeTransactionsServer) error {
×
6572

×
6573
        txClient, err := r.server.cc.Wallet.SubscribeTransactions()
×
6574
        if err != nil {
×
6575
                return err
×
6576
        }
×
6577
        defer txClient.Cancel()
×
6578
        rpcsLog.Infof("New transaction subscription")
×
6579

×
6580
        for {
×
6581
                select {
×
6582
                case tx := <-txClient.ConfirmedTransactions():
×
6583
                        detail := lnrpc.RPCTransaction(tx)
×
6584
                        if err := updateStream.Send(detail); err != nil {
×
6585
                                return err
×
6586
                        }
×
6587

6588
                case tx := <-txClient.UnconfirmedTransactions():
×
6589
                        detail := lnrpc.RPCTransaction(tx)
×
6590
                        if err := updateStream.Send(detail); err != nil {
×
6591
                                return err
×
6592
                        }
×
6593

6594
                // The response stream's context for whatever reason has been
6595
                // closed. If context is closed by an exceeded deadline we will
6596
                // return an error.
6597
                case <-updateStream.Context().Done():
×
6598
                        rpcsLog.Infof("Canceling transaction subscription")
×
6599
                        if errors.Is(updateStream.Context().Err(), context.Canceled) {
×
6600
                                return nil
×
6601
                        }
×
6602
                        return updateStream.Context().Err()
×
6603

6604
                case <-r.quit:
×
6605
                        return nil
×
6606
                }
6607
        }
6608
}
6609

6610
// GetTransactions returns a list of describing all the known transactions
6611
// relevant to the wallet.
6612
func (r *rpcServer) GetTransactions(ctx context.Context,
6613
        req *lnrpc.GetTransactionsRequest) (*lnrpc.TransactionDetails, error) {
3✔
6614

3✔
6615
        // To remain backwards compatible with the old api, default to the
3✔
6616
        // special case end height which will return transactions from the start
3✔
6617
        // height until the chain tip, including unconfirmed transactions.
3✔
6618
        var endHeight = btcwallet.UnconfirmedHeight
3✔
6619

3✔
6620
        // If the user has provided an end height, we overwrite our default.
3✔
6621
        if req.EndHeight != 0 {
6✔
6622
                endHeight = req.EndHeight
3✔
6623
        }
3✔
6624

6625
        txns, firstIdx, lastIdx, err :=
3✔
6626
                r.server.cc.Wallet.ListTransactionDetails(
3✔
6627
                        req.StartHeight, endHeight, req.Account,
3✔
6628
                        req.IndexOffset, req.MaxTransactions,
3✔
6629
                )
3✔
6630
        if err != nil {
3✔
6631
                return nil, err
×
6632
        }
×
6633

6634
        return lnrpc.RPCTransactionDetails(txns, firstIdx, lastIdx), nil
3✔
6635
}
6636

6637
// DescribeGraph returns a description of the latest graph state from the PoV
6638
// of the node. The graph information is partitioned into two components: all
6639
// the nodes/vertexes, and all the edges that connect the vertexes themselves.
6640
// As this is a directed graph, the edges also contain the node directional
6641
// specific routing policy which includes: the time lock delta, fee
6642
// information, etc.
6643
func (r *rpcServer) DescribeGraph(ctx context.Context,
6644
        req *lnrpc.ChannelGraphRequest) (*lnrpc.ChannelGraph, error) {
3✔
6645

3✔
6646
        resp := &lnrpc.ChannelGraph{}
3✔
6647
        includeUnannounced := req.IncludeUnannounced
3✔
6648

3✔
6649
        // Check to see if the cache is already populated, if so then we can
3✔
6650
        // just return it directly.
3✔
6651
        //
3✔
6652
        // TODO(roasbeef): move this to an interceptor level feature?
3✔
6653
        graphCacheActive := r.cfg.Caches.RPCGraphCacheDuration != 0
3✔
6654
        if graphCacheActive {
6✔
6655
                r.graphCache.Lock()
3✔
6656
                defer r.graphCache.Unlock()
3✔
6657

3✔
6658
                if r.describeGraphResp != nil {
6✔
6659
                        return r.describeGraphResp, nil
3✔
6660
                }
3✔
6661
        }
6662

6663
        // Obtain the pointer to the global singleton channel graph, this will
6664
        // provide a consistent view of the graph due to bolt db's
6665
        // transactional model.
6666
        graph := r.server.graphDB
3✔
6667

3✔
6668
        // First iterate through all the known nodes (connected or unconnected
3✔
6669
        // within the graph), collating their current state into the RPC
3✔
6670
        // response.
3✔
6671
        err := graph.ForEachNode(func(nodeTx graphdb.NodeRTx) error {
6✔
6672
                lnNode := marshalNode(nodeTx.Node())
3✔
6673

3✔
6674
                resp.Nodes = append(resp.Nodes, lnNode)
3✔
6675

3✔
6676
                return nil
3✔
6677
        })
3✔
6678
        if err != nil {
3✔
6679
                return nil, err
×
6680
        }
×
6681

6682
        // Next, for each active channel we know of within the graph, create a
6683
        // similar response which details both the edge information as well as
6684
        // the routing policies of th nodes connecting the two edges.
6685
        err = graph.ForEachChannel(func(edgeInfo *models.ChannelEdgeInfo,
3✔
6686
                c1, c2 *models.ChannelEdgePolicy) error {
6✔
6687

3✔
6688
                // Do not include unannounced channels unless specifically
3✔
6689
                // requested. Unannounced channels include both private channels as
3✔
6690
                // well as public channels whose authentication proof were not
3✔
6691
                // confirmed yet, hence were not announced.
3✔
6692
                if !includeUnannounced && edgeInfo.AuthProof == nil {
6✔
6693
                        return nil
3✔
6694
                }
3✔
6695

6696
                edge := marshalDBEdge(edgeInfo, c1, c2)
3✔
6697
                resp.Edges = append(resp.Edges, edge)
3✔
6698

3✔
6699
                return nil
3✔
6700
        })
6701
        if err != nil && !errors.Is(err, graphdb.ErrGraphNoEdgesFound) {
3✔
6702
                return nil, err
×
6703
        }
×
6704

6705
        // We still have the mutex held, so we can safely populate the cache
6706
        // now to save on GC churn for this query, but only if the cache isn't
6707
        // disabled.
6708
        if graphCacheActive {
6✔
6709
                r.describeGraphResp = resp
3✔
6710
        }
3✔
6711

6712
        return resp, nil
3✔
6713
}
6714

6715
// marshalExtraOpaqueData marshals the given tlv data. If the tlv stream is
6716
// malformed or empty, an empty map is returned. This makes the method safe to
6717
// use on unvalidated data.
6718
func marshalExtraOpaqueData(data []byte) map[uint64][]byte {
3✔
6719
        r := bytes.NewReader(data)
3✔
6720

3✔
6721
        tlvStream, err := tlv.NewStream()
3✔
6722
        if err != nil {
3✔
6723
                return nil
×
6724
        }
×
6725

6726
        // Since ExtraOpaqueData is provided by a potentially malicious peer,
6727
        // pass it into the P2P decoding variant.
6728
        parsedTypes, err := tlvStream.DecodeWithParsedTypesP2P(r)
3✔
6729
        if err != nil || len(parsedTypes) == 0 {
6✔
6730
                return nil
3✔
6731
        }
3✔
6732

6733
        records := make(map[uint64][]byte)
3✔
6734
        for k, v := range parsedTypes {
6✔
6735
                records[uint64(k)] = v
3✔
6736
        }
3✔
6737

6738
        return records
3✔
6739
}
6740

6741
// extractInboundFeeSafe tries to extract the inbound fee from the given extra
6742
// opaque data tlv block. If parsing fails, a zero inbound fee is returned. This
6743
// function is typically used on unvalidated data coming stored in the database.
6744
// There is not much we can do other than ignoring errors here.
6745
func extractInboundFeeSafe(data lnwire.ExtraOpaqueData) lnwire.Fee {
3✔
6746
        var inboundFee lnwire.Fee
3✔
6747

3✔
6748
        _, err := data.ExtractRecords(&inboundFee)
3✔
6749
        if err != nil {
3✔
6750
                // Return zero fee. Do not return the inboundFee variable
×
6751
                // because it may be undefined.
×
6752
                return lnwire.Fee{}
×
6753
        }
×
6754

6755
        return inboundFee
3✔
6756
}
6757

6758
func marshalDBEdge(edgeInfo *models.ChannelEdgeInfo,
6759
        c1, c2 *models.ChannelEdgePolicy) *lnrpc.ChannelEdge {
3✔
6760

3✔
6761
        // Make sure the policies match the node they belong to. c1 should point
3✔
6762
        // to the policy for NodeKey1, and c2 for NodeKey2.
3✔
6763
        if c1 != nil && c1.ChannelFlags&lnwire.ChanUpdateDirection == 1 ||
3✔
6764
                c2 != nil && c2.ChannelFlags&lnwire.ChanUpdateDirection == 0 {
3✔
6765

×
6766
                c2, c1 = c1, c2
×
6767
        }
×
6768

6769
        var lastUpdate int64
3✔
6770
        if c1 != nil {
6✔
6771
                lastUpdate = c1.LastUpdate.Unix()
3✔
6772
        }
3✔
6773
        if c2 != nil && c2.LastUpdate.Unix() > lastUpdate {
6✔
6774
                lastUpdate = c2.LastUpdate.Unix()
3✔
6775
        }
3✔
6776

6777
        customRecords := marshalExtraOpaqueData(edgeInfo.ExtraOpaqueData)
3✔
6778

3✔
6779
        edge := &lnrpc.ChannelEdge{
3✔
6780
                ChannelId: edgeInfo.ChannelID,
3✔
6781
                ChanPoint: edgeInfo.ChannelPoint.String(),
3✔
6782
                // TODO(roasbeef): update should be on edge info itself
3✔
6783
                LastUpdate:    uint32(lastUpdate),
3✔
6784
                Node1Pub:      hex.EncodeToString(edgeInfo.NodeKey1Bytes[:]),
3✔
6785
                Node2Pub:      hex.EncodeToString(edgeInfo.NodeKey2Bytes[:]),
3✔
6786
                Capacity:      int64(edgeInfo.Capacity),
3✔
6787
                CustomRecords: customRecords,
3✔
6788
        }
3✔
6789

3✔
6790
        if c1 != nil {
6✔
6791
                edge.Node1Policy = marshalDBRoutingPolicy(c1)
3✔
6792
        }
3✔
6793

6794
        if c2 != nil {
6✔
6795
                edge.Node2Policy = marshalDBRoutingPolicy(c2)
3✔
6796
        }
3✔
6797

6798
        return edge
3✔
6799
}
6800

6801
func marshalDBRoutingPolicy(
6802
        policy *models.ChannelEdgePolicy) *lnrpc.RoutingPolicy {
3✔
6803

3✔
6804
        disabled := policy.ChannelFlags&lnwire.ChanUpdateDisabled != 0
3✔
6805

3✔
6806
        customRecords := marshalExtraOpaqueData(policy.ExtraOpaqueData)
3✔
6807
        inboundFee := extractInboundFeeSafe(policy.ExtraOpaqueData)
3✔
6808

3✔
6809
        return &lnrpc.RoutingPolicy{
3✔
6810
                TimeLockDelta:    uint32(policy.TimeLockDelta),
3✔
6811
                MinHtlc:          int64(policy.MinHTLC),
3✔
6812
                MaxHtlcMsat:      uint64(policy.MaxHTLC),
3✔
6813
                FeeBaseMsat:      int64(policy.FeeBaseMSat),
3✔
6814
                FeeRateMilliMsat: int64(policy.FeeProportionalMillionths),
3✔
6815
                Disabled:         disabled,
3✔
6816
                LastUpdate:       uint32(policy.LastUpdate.Unix()),
3✔
6817
                CustomRecords:    customRecords,
3✔
6818

3✔
6819
                InboundFeeBaseMsat:      inboundFee.BaseFee,
3✔
6820
                InboundFeeRateMilliMsat: inboundFee.FeeRate,
3✔
6821
        }
3✔
6822
}
3✔
6823

6824
// GetNodeMetrics returns all available node metrics calculated from the
6825
// current channel graph.
6826
func (r *rpcServer) GetNodeMetrics(ctx context.Context,
6827
        req *lnrpc.NodeMetricsRequest) (*lnrpc.NodeMetricsResponse, error) {
×
6828

×
6829
        // Get requested metric types.
×
6830
        getCentrality := false
×
6831
        for _, t := range req.Types {
×
6832
                if t == lnrpc.NodeMetricType_BETWEENNESS_CENTRALITY {
×
6833
                        getCentrality = true
×
6834
                }
×
6835
        }
6836

6837
        // Only centrality can be requested for now.
6838
        if !getCentrality {
×
6839
                return nil, nil
×
6840
        }
×
6841

6842
        resp := &lnrpc.NodeMetricsResponse{
×
6843
                BetweennessCentrality: make(map[string]*lnrpc.FloatMetric),
×
6844
        }
×
6845

×
6846
        // Obtain the pointer to the global singleton channel graph, this will
×
6847
        // provide a consistent view of the graph due to bolt db's
×
6848
        // transactional model.
×
6849
        graph := r.server.graphDB
×
6850

×
6851
        // Calculate betweenness centrality if requested. Note that depending on the
×
6852
        // graph size, this may take up to a few minutes.
×
6853
        channelGraph := autopilot.ChannelGraphFromDatabase(graph)
×
6854
        centralityMetric, err := autopilot.NewBetweennessCentralityMetric(
×
6855
                runtime.NumCPU(),
×
6856
        )
×
6857
        if err != nil {
×
6858
                return nil, err
×
6859
        }
×
6860
        if err := centralityMetric.Refresh(channelGraph); err != nil {
×
6861
                return nil, err
×
6862
        }
×
6863

6864
        // Fill normalized and non normalized centrality.
6865
        centrality := centralityMetric.GetMetric(true)
×
6866
        for nodeID, val := range centrality {
×
6867
                resp.BetweennessCentrality[hex.EncodeToString(nodeID[:])] =
×
6868
                        &lnrpc.FloatMetric{
×
6869
                                NormalizedValue: val,
×
6870
                        }
×
6871
        }
×
6872

6873
        centrality = centralityMetric.GetMetric(false)
×
6874
        for nodeID, val := range centrality {
×
6875
                resp.BetweennessCentrality[hex.EncodeToString(nodeID[:])].Value = val
×
6876
        }
×
6877

6878
        return resp, nil
×
6879
}
6880

6881
// GetChanInfo returns the latest authenticated network announcement for the
6882
// given channel identified by either its channel ID or a channel outpoint. Both
6883
// uniquely identify the location of transaction's funding output within the
6884
// blockchain. The former is an 8-byte integer, while the latter is a string
6885
// formatted as funding_txid:output_index.
6886
func (r *rpcServer) GetChanInfo(_ context.Context,
6887
        in *lnrpc.ChanInfoRequest) (*lnrpc.ChannelEdge, error) {
3✔
6888

3✔
6889
        graph := r.server.graphDB
3✔
6890

3✔
6891
        var (
3✔
6892
                edgeInfo     *models.ChannelEdgeInfo
3✔
6893
                edge1, edge2 *models.ChannelEdgePolicy
3✔
6894
                err          error
3✔
6895
        )
3✔
6896

3✔
6897
        switch {
3✔
6898
        case in.ChanId != 0:
3✔
6899
                edgeInfo, edge1, edge2, err = graph.FetchChannelEdgesByID(
3✔
6900
                        in.ChanId,
3✔
6901
                )
3✔
6902

6903
        case in.ChanPoint != "":
3✔
6904
                var chanPoint *wire.OutPoint
3✔
6905
                chanPoint, err = wire.NewOutPointFromString(in.ChanPoint)
3✔
6906
                if err != nil {
3✔
6907
                        return nil, err
×
6908
                }
×
6909
                edgeInfo, edge1, edge2, err = graph.FetchChannelEdgesByOutpoint(
3✔
6910
                        chanPoint,
3✔
6911
                )
3✔
6912

6913
        default:
×
6914
                return nil, fmt.Errorf("specify either chan_id or chan_point")
×
6915
        }
6916
        if err != nil {
6✔
6917
                return nil, err
3✔
6918
        }
3✔
6919

6920
        // Convert the database's edge format into the network/RPC edge format
6921
        // which couples the edge itself along with the directional node
6922
        // routing policies of each node involved within the channel.
6923
        channelEdge := marshalDBEdge(edgeInfo, edge1, edge2)
3✔
6924

3✔
6925
        return channelEdge, nil
3✔
6926
}
6927

6928
// GetNodeInfo returns the latest advertised and aggregate authenticated
6929
// channel information for the specified node identified by its public key.
6930
func (r *rpcServer) GetNodeInfo(ctx context.Context,
6931
        in *lnrpc.NodeInfoRequest) (*lnrpc.NodeInfo, error) {
×
6932

×
6933
        graph := r.server.graphDB
×
6934

×
6935
        // First, parse the hex-encoded public key into a full in-memory public
×
6936
        // key object we can work with for querying.
×
6937
        pubKey, err := route.NewVertexFromStr(in.PubKey)
×
6938
        if err != nil {
×
6939
                return nil, err
×
6940
        }
×
6941

6942
        // With the public key decoded, attempt to fetch the node corresponding
6943
        // to this public key. If the node cannot be found, then an error will
6944
        // be returned.
6945
        node, err := graph.FetchLightningNode(pubKey)
×
6946
        switch {
×
6947
        case errors.Is(err, graphdb.ErrGraphNodeNotFound):
×
6948
                return nil, status.Error(codes.NotFound, err.Error())
×
6949
        case err != nil:
×
6950
                return nil, err
×
6951
        }
6952

6953
        // With the node obtained, we'll now iterate through all its out going
6954
        // edges to gather some basic statistics about its out going channels.
6955
        var (
×
6956
                numChannels   uint32
×
6957
                totalCapacity btcutil.Amount
×
6958
                channels      []*lnrpc.ChannelEdge
×
6959
        )
×
6960

×
6961
        err = graph.ForEachNodeChannel(node.PubKeyBytes,
×
6962
                func(_ kvdb.RTx, edge *models.ChannelEdgeInfo,
×
6963
                        c1, c2 *models.ChannelEdgePolicy) error {
×
6964

×
6965
                        numChannels++
×
6966
                        totalCapacity += edge.Capacity
×
6967

×
6968
                        // Only populate the node's channels if the user
×
6969
                        // requested them.
×
6970
                        if in.IncludeChannels {
×
6971
                                // Do not include unannounced channels - private
×
6972
                                // channels or public channels whose
×
6973
                                // authentication proof were not confirmed yet.
×
6974
                                if edge.AuthProof == nil {
×
6975
                                        return nil
×
6976
                                }
×
6977

6978
                                // Convert the database's edge format into the
6979
                                // network/RPC edge format.
6980
                                channelEdge := marshalDBEdge(edge, c1, c2)
×
6981
                                channels = append(channels, channelEdge)
×
6982
                        }
6983

6984
                        return nil
×
6985
                },
6986
        )
6987
        if err != nil {
×
6988
                return nil, err
×
6989
        }
×
6990

6991
        return &lnrpc.NodeInfo{
×
6992
                Node:          marshalNode(node),
×
6993
                NumChannels:   numChannels,
×
6994
                TotalCapacity: int64(totalCapacity),
×
6995
                Channels:      channels,
×
6996
        }, nil
×
6997
}
6998

6999
func marshalNode(node *models.LightningNode) *lnrpc.LightningNode {
3✔
7000
        nodeAddrs := make([]*lnrpc.NodeAddress, len(node.Addresses))
3✔
7001
        for i, addr := range node.Addresses {
6✔
7002
                nodeAddr := &lnrpc.NodeAddress{
3✔
7003
                        Network: addr.Network(),
3✔
7004
                        Addr:    addr.String(),
3✔
7005
                }
3✔
7006
                nodeAddrs[i] = nodeAddr
3✔
7007
        }
3✔
7008

7009
        features := invoicesrpc.CreateRPCFeatures(node.Features)
3✔
7010

3✔
7011
        customRecords := marshalExtraOpaqueData(node.ExtraOpaqueData)
3✔
7012

3✔
7013
        return &lnrpc.LightningNode{
3✔
7014
                LastUpdate:    uint32(node.LastUpdate.Unix()),
3✔
7015
                PubKey:        hex.EncodeToString(node.PubKeyBytes[:]),
3✔
7016
                Addresses:     nodeAddrs,
3✔
7017
                Alias:         node.Alias,
3✔
7018
                Color:         graphdb.EncodeHexColor(node.Color),
3✔
7019
                Features:      features,
3✔
7020
                CustomRecords: customRecords,
3✔
7021
        }
3✔
7022
}
7023

7024
// QueryRoutes attempts to query the daemons' Channel Router for a possible
7025
// route to a target destination capable of carrying a specific amount of
7026
// satoshis within the route's flow. The returned route contains the full
7027
// details required to craft and send an HTLC, also including the necessary
7028
// information that should be present within the Sphinx packet encapsulated
7029
// within the HTLC.
7030
//
7031
// TODO(roasbeef): should return a slice of routes in reality
7032
//   - create separate PR to send based on well formatted route
7033
func (r *rpcServer) QueryRoutes(ctx context.Context,
7034
        in *lnrpc.QueryRoutesRequest) (*lnrpc.QueryRoutesResponse, error) {
3✔
7035

3✔
7036
        return r.routerBackend.QueryRoutes(ctx, in)
3✔
7037
}
3✔
7038

7039
// GetNetworkInfo returns some basic stats about the known channel graph from
7040
// the PoV of the node.
7041
func (r *rpcServer) GetNetworkInfo(ctx context.Context,
7042
        _ *lnrpc.NetworkInfoRequest) (*lnrpc.NetworkInfo, error) {
×
7043

×
7044
        graph := r.server.graphDB
×
7045

×
7046
        var (
×
7047
                numNodes             uint32
×
7048
                numChannels          uint32
×
7049
                maxChanOut           uint32
×
7050
                totalNetworkCapacity btcutil.Amount
×
7051
                minChannelSize       btcutil.Amount = math.MaxInt64
×
7052
                maxChannelSize       btcutil.Amount
×
7053
                medianChanSize       btcutil.Amount
×
7054
        )
×
7055

×
7056
        // We'll use this map to de-duplicate channels during our traversal.
×
7057
        // This is needed since channels are directional, so there will be two
×
7058
        // edges for each channel within the graph.
×
7059
        seenChans := make(map[uint64]struct{})
×
7060

×
7061
        // We also keep a list of all encountered capacities, in order to
×
7062
        // calculate the median channel size.
×
7063
        var allChans []btcutil.Amount
×
7064

×
7065
        // We'll run through all the known nodes in the within our view of the
×
7066
        // network, tallying up the total number of nodes, and also gathering
×
7067
        // each node so we can measure the graph diameter and degree stats
×
7068
        // below.
×
7069
        err := graph.ForEachNodeCached(func(node route.Vertex,
×
7070
                edges map[uint64]*graphdb.DirectedChannel) error {
×
7071

×
7072
                // Increment the total number of nodes with each iteration.
×
7073
                numNodes++
×
7074

×
7075
                // For each channel we'll compute the out degree of each node,
×
7076
                // and also update our running tallies of the min/max channel
×
7077
                // capacity, as well as the total channel capacity. We pass
×
7078
                // through the db transaction from the outer view so we can
×
7079
                // re-use it within this inner view.
×
7080
                var outDegree uint32
×
7081
                for _, edge := range edges {
×
7082
                        // Bump up the out degree for this node for each
×
7083
                        // channel encountered.
×
7084
                        outDegree++
×
7085

×
7086
                        // If we've already seen this channel, then we'll
×
7087
                        // return early to ensure that we don't double-count
×
7088
                        // stats.
×
7089
                        if _, ok := seenChans[edge.ChannelID]; ok {
×
7090
                                return nil
×
7091
                        }
×
7092

7093
                        // Compare the capacity of this channel against the
7094
                        // running min/max to see if we should update the
7095
                        // extrema.
7096
                        chanCapacity := edge.Capacity
×
7097
                        if chanCapacity < minChannelSize {
×
7098
                                minChannelSize = chanCapacity
×
7099
                        }
×
7100
                        if chanCapacity > maxChannelSize {
×
7101
                                maxChannelSize = chanCapacity
×
7102
                        }
×
7103

7104
                        // Accumulate the total capacity of this channel to the
7105
                        // network wide-capacity.
7106
                        totalNetworkCapacity += chanCapacity
×
7107

×
7108
                        numChannels++
×
7109

×
7110
                        seenChans[edge.ChannelID] = struct{}{}
×
7111
                        allChans = append(allChans, edge.Capacity)
×
7112
                }
7113

7114
                // Finally, if the out degree of this node is greater than what
7115
                // we've seen so far, update the maxChanOut variable.
7116
                if outDegree > maxChanOut {
×
7117
                        maxChanOut = outDegree
×
7118
                }
×
7119

7120
                return nil
×
7121
        })
7122
        if err != nil {
×
7123
                return nil, err
×
7124
        }
×
7125

7126
        // Query the graph for the current number of zombie channels.
7127
        numZombies, err := graph.NumZombies()
×
7128
        if err != nil {
×
7129
                return nil, err
×
7130
        }
×
7131

7132
        // Find the median.
7133
        medianChanSize = autopilot.Median(allChans)
×
7134

×
7135
        // If we don't have any channels, then reset the minChannelSize to zero
×
7136
        // to avoid outputting NaN in encoded JSON.
×
7137
        if numChannels == 0 {
×
7138
                minChannelSize = 0
×
7139
        }
×
7140

7141
        // Graph diameter.
7142
        channelGraph := autopilot.ChannelGraphFromCachedDatabase(graph)
×
7143
        simpleGraph, err := autopilot.NewSimpleGraph(channelGraph)
×
7144
        if err != nil {
×
7145
                return nil, err
×
7146
        }
×
7147
        start := time.Now()
×
7148
        diameter := simpleGraph.DiameterRadialCutoff()
×
7149
        rpcsLog.Infof("elapsed time for diameter (%d) calculation: %v", diameter,
×
7150
                time.Since(start))
×
7151

×
7152
        // TODO(roasbeef): also add oldest channel?
×
7153
        netInfo := &lnrpc.NetworkInfo{
×
7154
                GraphDiameter:        diameter,
×
7155
                MaxOutDegree:         maxChanOut,
×
7156
                AvgOutDegree:         float64(2*numChannels) / float64(numNodes),
×
7157
                NumNodes:             numNodes,
×
7158
                NumChannels:          numChannels,
×
7159
                TotalNetworkCapacity: int64(totalNetworkCapacity),
×
7160
                AvgChannelSize:       float64(totalNetworkCapacity) / float64(numChannels),
×
7161

×
7162
                MinChannelSize:       int64(minChannelSize),
×
7163
                MaxChannelSize:       int64(maxChannelSize),
×
7164
                MedianChannelSizeSat: int64(medianChanSize),
×
7165
                NumZombieChans:       numZombies,
×
7166
        }
×
7167

×
7168
        // Similarly, if we don't have any channels, then we'll also set the
×
7169
        // average channel size to zero in order to avoid weird JSON encoding
×
7170
        // outputs.
×
7171
        if numChannels == 0 {
×
7172
                netInfo.AvgChannelSize = 0
×
7173
        }
×
7174

7175
        return netInfo, nil
×
7176
}
7177

7178
// StopDaemon will send a shutdown request to the interrupt handler, triggering
7179
// a graceful shutdown of the daemon.
7180
func (r *rpcServer) StopDaemon(_ context.Context,
7181
        _ *lnrpc.StopRequest) (*lnrpc.StopResponse, error) {
3✔
7182

3✔
7183
        // Before we even consider a shutdown, are we currently in recovery
3✔
7184
        // mode? We don't want to allow shutting down during recovery because
3✔
7185
        // that would mean the user would have to manually continue the rescan
3✔
7186
        // process next time by using `lncli unlock --recovery_window X`
3✔
7187
        // otherwise some funds wouldn't be picked up.
3✔
7188
        isRecoveryMode, progress, err := r.server.cc.Wallet.GetRecoveryInfo()
3✔
7189
        if err != nil {
3✔
7190
                return nil, fmt.Errorf("unable to get wallet recovery info: %w",
×
7191
                        err)
×
7192
        }
×
7193
        if isRecoveryMode && progress < 1 {
3✔
7194
                return nil, fmt.Errorf("wallet recovery in progress, cannot " +
×
7195
                        "shut down, please wait until rescan finishes")
×
7196
        }
×
7197

7198
        r.interceptor.RequestShutdown()
3✔
7199

3✔
7200
        return &lnrpc.StopResponse{
3✔
7201
                Status: "shutdown initiated, check logs for progress",
3✔
7202
        }, nil
3✔
7203
}
7204

7205
// SubscribeChannelGraph launches a streaming RPC that allows the caller to
7206
// receive notifications upon any changes the channel graph topology from the
7207
// review of the responding node. Events notified include: new nodes coming
7208
// online, nodes updating their authenticated attributes, new channels being
7209
// advertised, updates in the routing policy for a directional channel edge,
7210
// and finally when prior channels are closed on-chain.
7211
func (r *rpcServer) SubscribeChannelGraph(req *lnrpc.GraphTopologySubscription,
7212
        updateStream lnrpc.Lightning_SubscribeChannelGraphServer) error {
3✔
7213

3✔
7214
        // First, we start by subscribing to a new intent to receive
3✔
7215
        // notifications from the channel router.
3✔
7216
        client, err := r.server.graphDB.SubscribeTopology()
3✔
7217
        if err != nil {
3✔
7218
                return err
×
7219
        }
×
7220

7221
        // Ensure that the resources for the topology update client is cleaned
7222
        // up once either the server, or client exists.
7223
        defer client.Cancel()
3✔
7224

3✔
7225
        for {
6✔
7226
                select {
3✔
7227

7228
                // A new update has been sent by the channel router, we'll
7229
                // marshal it into the form expected by the gRPC client, then
7230
                // send it off.
7231
                case topChange, ok := <-client.TopologyChanges:
3✔
7232
                        // If the second value from the channel read is nil,
3✔
7233
                        // then this means that the channel router is exiting
3✔
7234
                        // or the notification client was canceled. So we'll
3✔
7235
                        // exit early.
3✔
7236
                        if !ok {
3✔
7237
                                return errors.New("server shutting down")
×
7238
                        }
×
7239

7240
                        // Convert the struct from the channel router into the
7241
                        // form expected by the gRPC service then send it off
7242
                        // to the client.
7243
                        graphUpdate := marshallTopologyChange(topChange)
3✔
7244
                        if err := updateStream.Send(graphUpdate); err != nil {
3✔
7245
                                return err
×
7246
                        }
×
7247

7248
                // The response stream's context for whatever reason has been
7249
                // closed. If context is closed by an exceeded deadline
7250
                // we will return an error.
7251
                case <-updateStream.Context().Done():
3✔
7252
                        if errors.Is(updateStream.Context().Err(), context.Canceled) {
6✔
7253
                                return nil
3✔
7254
                        }
3✔
7255
                        return updateStream.Context().Err()
×
7256

7257
                // The server is quitting, so we'll exit immediately. Returning
7258
                // nil will close the clients read end of the stream.
7259
                case <-r.quit:
×
7260
                        return nil
×
7261
                }
7262
        }
7263
}
7264

7265
// marshallTopologyChange performs a mapping from the topology change struct
7266
// returned by the router to the form of notifications expected by the current
7267
// gRPC service.
7268
func marshallTopologyChange(
7269
        topChange *graphdb.TopologyChange) *lnrpc.GraphTopologyUpdate {
3✔
7270

3✔
7271
        // encodeKey is a simple helper function that converts a live public
3✔
7272
        // key into a hex-encoded version of the compressed serialization for
3✔
7273
        // the public key.
3✔
7274
        encodeKey := func(k *btcec.PublicKey) string {
6✔
7275
                return hex.EncodeToString(k.SerializeCompressed())
3✔
7276
        }
3✔
7277

7278
        nodeUpdates := make([]*lnrpc.NodeUpdate, len(topChange.NodeUpdates))
3✔
7279
        for i, nodeUpdate := range topChange.NodeUpdates {
6✔
7280
                nodeAddrs := make(
3✔
7281
                        []*lnrpc.NodeAddress, 0, len(nodeUpdate.Addresses),
3✔
7282
                )
3✔
7283
                for _, addr := range nodeUpdate.Addresses {
6✔
7284
                        nodeAddr := &lnrpc.NodeAddress{
3✔
7285
                                Network: addr.Network(),
3✔
7286
                                Addr:    addr.String(),
3✔
7287
                        }
3✔
7288
                        nodeAddrs = append(nodeAddrs, nodeAddr)
3✔
7289
                }
3✔
7290

7291
                addrs := make([]string, len(nodeUpdate.Addresses))
3✔
7292
                for i, addr := range nodeUpdate.Addresses {
6✔
7293
                        addrs[i] = addr.String()
3✔
7294
                }
3✔
7295

7296
                nodeUpdates[i] = &lnrpc.NodeUpdate{
3✔
7297
                        Addresses:     addrs,
3✔
7298
                        NodeAddresses: nodeAddrs,
3✔
7299
                        IdentityKey:   encodeKey(nodeUpdate.IdentityKey),
3✔
7300
                        Alias:         nodeUpdate.Alias,
3✔
7301
                        Color:         nodeUpdate.Color,
3✔
7302
                        Features: invoicesrpc.CreateRPCFeatures(
3✔
7303
                                nodeUpdate.Features,
3✔
7304
                        ),
3✔
7305
                }
3✔
7306
        }
7307

7308
        channelUpdates := make([]*lnrpc.ChannelEdgeUpdate, len(topChange.ChannelEdgeUpdates))
3✔
7309
        for i, channelUpdate := range topChange.ChannelEdgeUpdates {
6✔
7310

3✔
7311
                customRecords := marshalExtraOpaqueData(
3✔
7312
                        channelUpdate.ExtraOpaqueData,
3✔
7313
                )
3✔
7314
                inboundFee := extractInboundFeeSafe(
3✔
7315
                        channelUpdate.ExtraOpaqueData,
3✔
7316
                )
3✔
7317

3✔
7318
                channelUpdates[i] = &lnrpc.ChannelEdgeUpdate{
3✔
7319
                        ChanId: channelUpdate.ChanID,
3✔
7320
                        ChanPoint: &lnrpc.ChannelPoint{
3✔
7321
                                FundingTxid: &lnrpc.ChannelPoint_FundingTxidBytes{
3✔
7322
                                        FundingTxidBytes: channelUpdate.ChanPoint.Hash[:],
3✔
7323
                                },
3✔
7324
                                OutputIndex: channelUpdate.ChanPoint.Index,
3✔
7325
                        },
3✔
7326
                        Capacity: int64(channelUpdate.Capacity),
3✔
7327
                        RoutingPolicy: &lnrpc.RoutingPolicy{
3✔
7328
                                TimeLockDelta: uint32(
3✔
7329
                                        channelUpdate.TimeLockDelta,
3✔
7330
                                ),
3✔
7331
                                MinHtlc: int64(
3✔
7332
                                        channelUpdate.MinHTLC,
3✔
7333
                                ),
3✔
7334
                                MaxHtlcMsat: uint64(
3✔
7335
                                        channelUpdate.MaxHTLC,
3✔
7336
                                ),
3✔
7337
                                FeeBaseMsat: int64(
3✔
7338
                                        channelUpdate.BaseFee,
3✔
7339
                                ),
3✔
7340
                                FeeRateMilliMsat: int64(
3✔
7341
                                        channelUpdate.FeeRate,
3✔
7342
                                ),
3✔
7343
                                Disabled:                channelUpdate.Disabled,
3✔
7344
                                InboundFeeBaseMsat:      inboundFee.BaseFee,
3✔
7345
                                InboundFeeRateMilliMsat: inboundFee.FeeRate,
3✔
7346
                                CustomRecords:           customRecords,
3✔
7347
                        },
3✔
7348
                        AdvertisingNode: encodeKey(channelUpdate.AdvertisingNode),
3✔
7349
                        ConnectingNode:  encodeKey(channelUpdate.ConnectingNode),
3✔
7350
                }
3✔
7351
        }
3✔
7352

7353
        closedChans := make([]*lnrpc.ClosedChannelUpdate, len(topChange.ClosedChannels))
3✔
7354
        for i, closedChan := range topChange.ClosedChannels {
6✔
7355
                closedChans[i] = &lnrpc.ClosedChannelUpdate{
3✔
7356
                        ChanId:       closedChan.ChanID,
3✔
7357
                        Capacity:     int64(closedChan.Capacity),
3✔
7358
                        ClosedHeight: closedChan.ClosedHeight,
3✔
7359
                        ChanPoint: &lnrpc.ChannelPoint{
3✔
7360
                                FundingTxid: &lnrpc.ChannelPoint_FundingTxidBytes{
3✔
7361
                                        FundingTxidBytes: closedChan.ChanPoint.Hash[:],
3✔
7362
                                },
3✔
7363
                                OutputIndex: closedChan.ChanPoint.Index,
3✔
7364
                        },
3✔
7365
                }
3✔
7366
        }
3✔
7367

7368
        return &lnrpc.GraphTopologyUpdate{
3✔
7369
                NodeUpdates:    nodeUpdates,
3✔
7370
                ChannelUpdates: channelUpdates,
3✔
7371
                ClosedChans:    closedChans,
3✔
7372
        }
3✔
7373
}
7374

7375
// ListPayments returns a list of outgoing payments determined by a paginated
7376
// database query.
7377
func (r *rpcServer) ListPayments(ctx context.Context,
7378
        req *lnrpc.ListPaymentsRequest) (*lnrpc.ListPaymentsResponse, error) {
3✔
7379

3✔
7380
        // If both dates are set, we check that the start date is less than the
3✔
7381
        // end date, otherwise we'll get an empty result.
3✔
7382
        if req.CreationDateStart != 0 && req.CreationDateEnd != 0 {
3✔
7383
                if req.CreationDateStart >= req.CreationDateEnd {
×
7384
                        return nil, fmt.Errorf("start date(%v) must be before "+
×
7385
                                "end date(%v)", req.CreationDateStart,
×
7386
                                req.CreationDateEnd)
×
7387
                }
×
7388
        }
7389

7390
        query := channeldb.PaymentsQuery{
3✔
7391
                IndexOffset:       req.IndexOffset,
3✔
7392
                MaxPayments:       req.MaxPayments,
3✔
7393
                Reversed:          req.Reversed,
3✔
7394
                IncludeIncomplete: req.IncludeIncomplete,
3✔
7395
                CountTotal:        req.CountTotalPayments,
3✔
7396
                CreationDateStart: int64(req.CreationDateStart),
3✔
7397
                CreationDateEnd:   int64(req.CreationDateEnd),
3✔
7398
        }
3✔
7399

3✔
7400
        // If the maximum number of payments wasn't specified, then we'll
3✔
7401
        // default to return the maximal number of payments representable.
3✔
7402
        if req.MaxPayments == 0 {
6✔
7403
                query.MaxPayments = math.MaxUint64
3✔
7404
        }
3✔
7405

7406
        paymentsQuerySlice, err := r.server.miscDB.QueryPayments(query)
3✔
7407
        if err != nil {
3✔
7408
                return nil, err
×
7409
        }
×
7410

7411
        paymentsResp := &lnrpc.ListPaymentsResponse{
3✔
7412
                LastIndexOffset:  paymentsQuerySlice.LastIndexOffset,
3✔
7413
                FirstIndexOffset: paymentsQuerySlice.FirstIndexOffset,
3✔
7414
                TotalNumPayments: paymentsQuerySlice.TotalCount,
3✔
7415
        }
3✔
7416

3✔
7417
        for _, payment := range paymentsQuerySlice.Payments {
6✔
7418
                payment := payment
3✔
7419

3✔
7420
                rpcPayment, err := r.routerBackend.MarshallPayment(payment)
3✔
7421
                if err != nil {
3✔
7422
                        return nil, err
×
7423
                }
×
7424

7425
                paymentsResp.Payments = append(
3✔
7426
                        paymentsResp.Payments, rpcPayment,
3✔
7427
                )
3✔
7428
        }
7429

7430
        return paymentsResp, nil
3✔
7431
}
7432

7433
// DeletePayment deletes a payment from the DB given its payment hash. If
7434
// failedHtlcsOnly is set, only failed HTLC attempts of the payment will be
7435
// deleted.
7436
func (r *rpcServer) DeletePayment(ctx context.Context,
7437
        req *lnrpc.DeletePaymentRequest) (
7438
        *lnrpc.DeletePaymentResponse, error) {
×
7439

×
7440
        hash, err := lntypes.MakeHash(req.PaymentHash)
×
7441
        if err != nil {
×
7442
                return nil, err
×
7443
        }
×
7444

7445
        rpcsLog.Infof("[DeletePayment] payment_identifier=%v, "+
×
7446
                "failed_htlcs_only=%v", hash, req.FailedHtlcsOnly)
×
7447

×
7448
        err = r.server.miscDB.DeletePayment(hash, req.FailedHtlcsOnly)
×
7449
        if err != nil {
×
7450
                return nil, err
×
7451
        }
×
7452

7453
        return &lnrpc.DeletePaymentResponse{
×
7454
                Status: "payment deleted",
×
7455
        }, nil
×
7456
}
7457

7458
// DeleteAllPayments deletes all outgoing payments from DB.
7459
func (r *rpcServer) DeleteAllPayments(ctx context.Context,
7460
        req *lnrpc.DeleteAllPaymentsRequest) (
7461
        *lnrpc.DeleteAllPaymentsResponse, error) {
3✔
7462

3✔
7463
        switch {
3✔
7464
        // Since this is a destructive operation, at least one of the options
7465
        // must be set to true.
7466
        case !req.AllPayments && !req.FailedPaymentsOnly &&
7467
                !req.FailedHtlcsOnly:
×
7468

×
7469
                return nil, fmt.Errorf("at least one of the options " +
×
7470
                        "`all_payments`, `failed_payments_only`, or " +
×
7471
                        "`failed_htlcs_only` must be set to true")
×
7472

7473
        // `all_payments` cannot be true with `failed_payments_only` or
7474
        // `failed_htlcs_only`. `all_payments` includes all records, making
7475
        // these options contradictory.
7476
        case req.AllPayments &&
7477
                (req.FailedPaymentsOnly || req.FailedHtlcsOnly):
×
7478

×
7479
                return nil, fmt.Errorf("`all_payments` cannot be set to true " +
×
7480
                        "while either `failed_payments_only` or " +
×
7481
                        "`failed_htlcs_only` is also set to true")
×
7482
        }
7483

7484
        rpcsLog.Infof("[DeleteAllPayments] failed_payments_only=%v, "+
3✔
7485
                "failed_htlcs_only=%v", req.FailedPaymentsOnly,
3✔
7486
                req.FailedHtlcsOnly)
3✔
7487

3✔
7488
        numDeletedPayments, err := r.server.miscDB.DeletePayments(
3✔
7489
                req.FailedPaymentsOnly, req.FailedHtlcsOnly,
3✔
7490
        )
3✔
7491
        if err != nil {
3✔
7492
                return nil, err
×
7493
        }
×
7494

7495
        return &lnrpc.DeleteAllPaymentsResponse{
3✔
7496
                Status: fmt.Sprintf("%v payments deleted, failed_htlcs_only=%v",
3✔
7497
                        numDeletedPayments, req.FailedHtlcsOnly),
3✔
7498
        }, nil
3✔
7499
}
7500

7501
// DebugLevel allows a caller to programmatically set the logging verbosity of
7502
// lnd. The logging can be targeted according to a coarse daemon-wide logging
7503
// level, or in a granular fashion to specify the logging for a target
7504
// sub-system.
7505
func (r *rpcServer) DebugLevel(ctx context.Context,
7506
        req *lnrpc.DebugLevelRequest) (*lnrpc.DebugLevelResponse, error) {
×
7507

×
7508
        // If show is set, then we simply print out the list of available
×
7509
        // sub-systems.
×
7510
        if req.Show {
×
7511
                return &lnrpc.DebugLevelResponse{
×
7512
                        SubSystems: strings.Join(
×
7513
                                r.cfg.SubLogMgr.SupportedSubsystems(), " ",
×
7514
                        ),
×
7515
                }, nil
×
7516
        }
×
7517

7518
        rpcsLog.Infof("[debuglevel] changing debug level to: %v", req.LevelSpec)
×
7519

×
7520
        // Otherwise, we'll attempt to set the logging level using the
×
7521
        // specified level spec.
×
7522
        err := build.ParseAndSetDebugLevels(req.LevelSpec, r.cfg.SubLogMgr)
×
7523
        if err != nil {
×
7524
                return nil, err
×
7525
        }
×
7526

7527
        subLoggers := r.cfg.SubLogMgr.SubLoggers()
×
7528
        // Sort alphabetically by subsystem name.
×
7529
        var tags []string
×
7530
        for t := range subLoggers {
×
7531
                tags = append(tags, t)
×
7532
        }
×
7533
        sort.Strings(tags)
×
7534

×
7535
        // Create the log levels string.
×
7536
        var logLevels []string
×
7537
        for _, t := range tags {
×
7538
                logLevels = append(logLevels, fmt.Sprintf("%s=%s", t,
×
7539
                        subLoggers[t].Level().String()))
×
7540
        }
×
7541
        logLevelsString := strings.Join(logLevels, ", ")
×
7542

×
7543
        // Propagate the new config level to the main config struct.
×
7544
        r.cfg.DebugLevel = logLevelsString
×
7545

×
7546
        return &lnrpc.DebugLevelResponse{
×
7547
                SubSystems: logLevelsString,
×
7548
        }, nil
×
7549
}
7550

7551
// DecodePayReq takes an encoded payment request string and attempts to decode
7552
// it, returning a full description of the conditions encoded within the
7553
// payment request.
7554
func (r *rpcServer) DecodePayReq(ctx context.Context,
7555
        req *lnrpc.PayReqString) (*lnrpc.PayReq, error) {
3✔
7556

3✔
7557
        rpcsLog.Tracef("[decodepayreq] decoding: %v", req.PayReq)
3✔
7558

3✔
7559
        // Fist we'll attempt to decode the payment request string, if the
3✔
7560
        // request is invalid or the checksum doesn't match, then we'll exit
3✔
7561
        // here with an error.
3✔
7562
        payReq, err := zpay32.Decode(req.PayReq, r.cfg.ActiveNetParams.Params)
3✔
7563
        if err != nil {
3✔
7564
                return nil, err
×
7565
        }
×
7566

7567
        // Let the fields default to empty strings.
7568
        desc := ""
3✔
7569
        if payReq.Description != nil {
6✔
7570
                desc = *payReq.Description
3✔
7571
        }
3✔
7572

7573
        descHash := []byte("")
3✔
7574
        if payReq.DescriptionHash != nil {
3✔
7575
                descHash = payReq.DescriptionHash[:]
×
7576
        }
×
7577

7578
        fallbackAddr := ""
3✔
7579
        if payReq.FallbackAddr != nil {
3✔
7580
                fallbackAddr = payReq.FallbackAddr.String()
×
7581
        }
×
7582

7583
        // Expiry time will default to 3600 seconds if not specified
7584
        // explicitly.
7585
        expiry := int64(payReq.Expiry().Seconds())
3✔
7586

3✔
7587
        // Convert between the `lnrpc` and `routing` types.
3✔
7588
        routeHints := invoicesrpc.CreateRPCRouteHints(payReq.RouteHints)
3✔
7589

3✔
7590
        blindedPaymentPaths, err := invoicesrpc.CreateRPCBlindedPayments(
3✔
7591
                payReq.BlindedPaymentPaths,
3✔
7592
        )
3✔
7593
        if err != nil {
3✔
7594
                return nil, err
×
7595
        }
×
7596

7597
        var amtSat, amtMsat int64
3✔
7598
        if payReq.MilliSat != nil {
6✔
7599
                amtSat = int64(payReq.MilliSat.ToSatoshis())
3✔
7600
                amtMsat = int64(*payReq.MilliSat)
3✔
7601
        }
3✔
7602

7603
        // Extract the payment address from the payment request, if present.
7604
        paymentAddr := payReq.PaymentAddr.UnwrapOr([32]byte{})
3✔
7605

3✔
7606
        dest := payReq.Destination.SerializeCompressed()
3✔
7607
        return &lnrpc.PayReq{
3✔
7608
                Destination:     hex.EncodeToString(dest),
3✔
7609
                PaymentHash:     hex.EncodeToString(payReq.PaymentHash[:]),
3✔
7610
                NumSatoshis:     amtSat,
3✔
7611
                NumMsat:         amtMsat,
3✔
7612
                Timestamp:       payReq.Timestamp.Unix(),
3✔
7613
                Description:     desc,
3✔
7614
                DescriptionHash: hex.EncodeToString(descHash[:]),
3✔
7615
                FallbackAddr:    fallbackAddr,
3✔
7616
                Expiry:          expiry,
3✔
7617
                CltvExpiry:      int64(payReq.MinFinalCLTVExpiry()),
3✔
7618
                RouteHints:      routeHints,
3✔
7619
                BlindedPaths:    blindedPaymentPaths,
3✔
7620
                PaymentAddr:     paymentAddr[:],
3✔
7621
                Features:        invoicesrpc.CreateRPCFeatures(payReq.Features),
3✔
7622
        }, nil
3✔
7623
}
7624

7625
// feeBase is the fixed point that fee rate computation are performed over.
7626
// Nodes on the network advertise their fee rate using this point as a base.
7627
// This means that the minimal possible fee rate if 1e-6, or 0.000001, or
7628
// 0.0001%.
7629
const feeBase float64 = 1000000
7630

7631
// FeeReport allows the caller to obtain a report detailing the current fee
7632
// schedule enforced by the node globally for each channel.
7633
func (r *rpcServer) FeeReport(ctx context.Context,
7634
        _ *lnrpc.FeeReportRequest) (*lnrpc.FeeReportResponse, error) {
3✔
7635

3✔
7636
        channelGraph := r.server.graphDB
3✔
7637
        selfNode, err := channelGraph.SourceNode()
3✔
7638
        if err != nil {
3✔
7639
                return nil, err
×
7640
        }
×
7641

7642
        var feeReports []*lnrpc.ChannelFeeReport
3✔
7643
        err = channelGraph.ForEachNodeChannel(selfNode.PubKeyBytes,
3✔
7644
                func(_ kvdb.RTx, chanInfo *models.ChannelEdgeInfo,
3✔
7645
                        edgePolicy, _ *models.ChannelEdgePolicy) error {
6✔
7646

3✔
7647
                        // Self node should always have policies for its
3✔
7648
                        // channels.
3✔
7649
                        if edgePolicy == nil {
3✔
7650
                                return fmt.Errorf("no policy for outgoing "+
×
7651
                                        "channel %v ", chanInfo.ChannelID)
×
7652
                        }
×
7653

7654
                        // We'll compute the effective fee rate by converting
7655
                        // from a fixed point fee rate to a floating point fee
7656
                        // rate. The fee rate field in the database the amount
7657
                        // of mSAT charged per 1mil mSAT sent, so will divide by
7658
                        // this to get the proper fee rate.
7659
                        feeRateFixedPoint :=
3✔
7660
                                edgePolicy.FeeProportionalMillionths
3✔
7661
                        feeRate := float64(feeRateFixedPoint) / feeBase
3✔
7662

3✔
7663
                        // Decode inbound fee from extra data.
3✔
7664
                        var inboundFee lnwire.Fee
3✔
7665
                        _, err := edgePolicy.ExtraOpaqueData.ExtractRecords(
3✔
7666
                                &inboundFee,
3✔
7667
                        )
3✔
7668
                        if err != nil {
3✔
7669
                                return err
×
7670
                        }
×
7671

7672
                        // TODO(roasbeef): also add stats for revenue for each
7673
                        // channel
7674
                        feeReports = append(feeReports, &lnrpc.ChannelFeeReport{
3✔
7675
                                ChanId:       chanInfo.ChannelID,
3✔
7676
                                ChannelPoint: chanInfo.ChannelPoint.String(),
3✔
7677
                                BaseFeeMsat:  int64(edgePolicy.FeeBaseMSat),
3✔
7678
                                FeePerMil:    int64(feeRateFixedPoint),
3✔
7679
                                FeeRate:      feeRate,
3✔
7680

3✔
7681
                                InboundBaseFeeMsat: inboundFee.BaseFee,
3✔
7682
                                InboundFeePerMil:   inboundFee.FeeRate,
3✔
7683
                        })
3✔
7684

3✔
7685
                        return nil
3✔
7686
                },
7687
        )
7688
        if err != nil {
3✔
7689
                return nil, err
×
7690
        }
×
7691

7692
        fwdEventLog := r.server.miscDB.ForwardingLog()
3✔
7693

3✔
7694
        // computeFeeSum is a helper function that computes the total fees for
3✔
7695
        // a particular time slice described by a forwarding event query.
3✔
7696
        computeFeeSum := func(query channeldb.ForwardingEventQuery) (lnwire.MilliSatoshi, error) {
6✔
7697

3✔
7698
                var totalFees lnwire.MilliSatoshi
3✔
7699

3✔
7700
                // We'll continue to fetch the next query and accumulate the
3✔
7701
                // fees until the next query returns no events.
3✔
7702
                for {
6✔
7703
                        timeSlice, err := fwdEventLog.Query(query)
3✔
7704
                        if err != nil {
3✔
7705
                                return 0, err
×
7706
                        }
×
7707

7708
                        // If the timeslice is empty, then we'll return as
7709
                        // we've retrieved all the entries in this range.
7710
                        if len(timeSlice.ForwardingEvents) == 0 {
6✔
7711
                                break
3✔
7712
                        }
7713

7714
                        // Otherwise, we'll tally up an accumulate the total
7715
                        // fees for this time slice.
7716
                        for _, event := range timeSlice.ForwardingEvents {
6✔
7717
                                fee := event.AmtIn - event.AmtOut
3✔
7718
                                totalFees += fee
3✔
7719
                        }
3✔
7720

7721
                        // We'll now take the last offset index returned as
7722
                        // part of this response, and modify our query to start
7723
                        // at this index. This has a pagination effect in the
7724
                        // case that our query bounds has more than 100k
7725
                        // entries.
7726
                        query.IndexOffset = timeSlice.LastIndexOffset
3✔
7727
                }
7728

7729
                return totalFees, nil
3✔
7730
        }
7731

7732
        now := time.Now()
3✔
7733

3✔
7734
        // Before we perform the queries below, we'll instruct the switch to
3✔
7735
        // flush any pending events to disk. This ensure we get a complete
3✔
7736
        // snapshot at this particular time.
3✔
7737
        if err := r.server.htlcSwitch.FlushForwardingEvents(); err != nil {
3✔
7738
                return nil, fmt.Errorf("unable to flush forwarding "+
×
7739
                        "events: %v", err)
×
7740
        }
×
7741

7742
        // In addition to returning the current fee schedule for each channel.
7743
        // We'll also perform a series of queries to obtain the total fees
7744
        // earned over the past day, week, and month.
7745
        dayQuery := channeldb.ForwardingEventQuery{
3✔
7746
                StartTime:    now.Add(-time.Hour * 24),
3✔
7747
                EndTime:      now,
3✔
7748
                NumMaxEvents: 1000,
3✔
7749
        }
3✔
7750
        dayFees, err := computeFeeSum(dayQuery)
3✔
7751
        if err != nil {
3✔
7752
                return nil, fmt.Errorf("unable to retrieve day fees: %w", err)
×
7753
        }
×
7754

7755
        weekQuery := channeldb.ForwardingEventQuery{
3✔
7756
                StartTime:    now.Add(-time.Hour * 24 * 7),
3✔
7757
                EndTime:      now,
3✔
7758
                NumMaxEvents: 1000,
3✔
7759
        }
3✔
7760
        weekFees, err := computeFeeSum(weekQuery)
3✔
7761
        if err != nil {
3✔
7762
                return nil, fmt.Errorf("unable to retrieve day fees: %w", err)
×
7763
        }
×
7764

7765
        monthQuery := channeldb.ForwardingEventQuery{
3✔
7766
                StartTime:    now.Add(-time.Hour * 24 * 30),
3✔
7767
                EndTime:      now,
3✔
7768
                NumMaxEvents: 1000,
3✔
7769
        }
3✔
7770
        monthFees, err := computeFeeSum(monthQuery)
3✔
7771
        if err != nil {
3✔
7772
                return nil, fmt.Errorf("unable to retrieve day fees: %w", err)
×
7773
        }
×
7774

7775
        return &lnrpc.FeeReportResponse{
3✔
7776
                ChannelFees: feeReports,
3✔
7777
                DayFeeSum:   uint64(dayFees.ToSatoshis()),
3✔
7778
                WeekFeeSum:  uint64(weekFees.ToSatoshis()),
3✔
7779
                MonthFeeSum: uint64(monthFees.ToSatoshis()),
3✔
7780
        }, nil
3✔
7781
}
7782

7783
// minFeeRate is the smallest permitted fee rate within the network. This is
7784
// derived by the fact that fee rates are computed using a fixed point of
7785
// 1,000,000. As a result, the smallest representable fee rate is 1e-6, or
7786
// 0.000001, or 0.0001%.
7787
const minFeeRate = 1e-6
7788

7789
// UpdateChannelPolicy allows the caller to update the channel forwarding policy
7790
// for all channels globally, or a particular channel.
7791
func (r *rpcServer) UpdateChannelPolicy(ctx context.Context,
7792
        req *lnrpc.PolicyUpdateRequest) (*lnrpc.PolicyUpdateResponse, error) {
3✔
7793

3✔
7794
        var targetChans []wire.OutPoint
3✔
7795
        switch scope := req.Scope.(type) {
3✔
7796
        // If the request is targeting all active channels, then we don't need
7797
        // target any channels by their channel point.
7798
        case *lnrpc.PolicyUpdateRequest_Global:
3✔
7799

7800
        // Otherwise, we're targeting an individual channel by its channel
7801
        // point.
7802
        case *lnrpc.PolicyUpdateRequest_ChanPoint:
3✔
7803
                txid, err := lnrpc.GetChanPointFundingTxid(scope.ChanPoint)
3✔
7804
                if err != nil {
3✔
7805
                        return nil, err
×
7806
                }
×
7807
                targetChans = append(targetChans, wire.OutPoint{
3✔
7808
                        Hash:  *txid,
3✔
7809
                        Index: scope.ChanPoint.OutputIndex,
3✔
7810
                })
3✔
7811
        default:
×
7812
                return nil, fmt.Errorf("unknown scope: %v", scope)
×
7813
        }
7814

7815
        var feeRateFixed uint32
3✔
7816

3✔
7817
        switch {
3✔
7818
        // The request should use either the fee rate in percent, or the new
7819
        // ppm rate, but not both.
7820
        case req.FeeRate != 0 && req.FeeRatePpm != 0:
×
7821
                errMsg := "cannot set both FeeRate and FeeRatePpm at the " +
×
7822
                        "same time"
×
7823

×
7824
                return nil, status.Errorf(codes.InvalidArgument, errMsg)
×
7825

7826
        // If the request is using fee_rate.
7827
        case req.FeeRate != 0:
3✔
7828
                // As a sanity check, if the fee isn't zero, we'll ensure that
3✔
7829
                // the passed fee rate is below 1e-6, or the lowest allowed
3✔
7830
                // non-zero fee rate expressible within the protocol.
3✔
7831
                if req.FeeRate != 0 && req.FeeRate < minFeeRate {
3✔
7832
                        return nil, fmt.Errorf("fee rate of %v is too "+
×
7833
                                "small, min fee rate is %v", req.FeeRate,
×
7834
                                minFeeRate)
×
7835
                }
×
7836

7837
                // We'll also need to convert the floating point fee rate we
7838
                // accept over RPC to the fixed point rate that we use within
7839
                // the protocol. We do this by multiplying the passed fee rate
7840
                // by the fee base. This gives us the fixed point, scaled by 1
7841
                // million that's used within the protocol.
7842
                //
7843
                // Because of the inaccurate precision of the IEEE 754
7844
                // standard, we need to round the product of feerate and
7845
                // feebase.
7846
                feeRateFixed = uint32(math.Round(req.FeeRate * feeBase))
3✔
7847

7848
        // Otherwise, we use the fee_rate_ppm parameter.
7849
        case req.FeeRatePpm != 0:
3✔
7850
                feeRateFixed = req.FeeRatePpm
3✔
7851
        }
7852

7853
        // We'll also ensure that the user isn't setting a CLTV delta that
7854
        // won't give outgoing HTLCs enough time to fully resolve if needed.
7855
        if req.TimeLockDelta < minTimeLockDelta {
3✔
7856
                return nil, fmt.Errorf("time lock delta of %v is too small, "+
×
7857
                        "minimum supported is %v", req.TimeLockDelta,
×
7858
                        minTimeLockDelta)
×
7859
        } else if req.TimeLockDelta > uint32(MaxTimeLockDelta) {
3✔
7860
                return nil, fmt.Errorf("time lock delta of %v is too big, "+
×
7861
                        "maximum supported is %v", req.TimeLockDelta,
×
7862
                        MaxTimeLockDelta)
×
7863
        }
×
7864

7865
        // By default, positive inbound fees are rejected.
7866
        if !r.cfg.AcceptPositiveInboundFees && req.InboundFee != nil {
6✔
7867
                if req.InboundFee.BaseFeeMsat > 0 {
3✔
7868
                        return nil, fmt.Errorf("positive values for inbound "+
×
7869
                                "base fee msat are not supported: %v",
×
7870
                                req.InboundFee.BaseFeeMsat)
×
7871
                }
×
7872
                if req.InboundFee.FeeRatePpm > 0 {
3✔
7873
                        return nil, fmt.Errorf("positive values for inbound "+
×
7874
                                "fee rate ppm are not supported: %v",
×
7875
                                req.InboundFee.FeeRatePpm)
×
7876
                }
×
7877
        }
7878

7879
        // If no inbound fees have been specified, we indicate with an empty
7880
        // option that the previous inbound fee should be retained during the
7881
        // edge update.
7882
        inboundFee := fn.None[models.InboundFee]()
3✔
7883
        if req.InboundFee != nil {
6✔
7884
                inboundFee = fn.Some(models.InboundFee{
3✔
7885
                        Base: req.InboundFee.BaseFeeMsat,
3✔
7886
                        Rate: req.InboundFee.FeeRatePpm,
3✔
7887
                })
3✔
7888
        }
3✔
7889

7890
        baseFeeMsat := lnwire.MilliSatoshi(req.BaseFeeMsat)
3✔
7891
        feeSchema := routing.FeeSchema{
3✔
7892
                BaseFee:    baseFeeMsat,
3✔
7893
                FeeRate:    feeRateFixed,
3✔
7894
                InboundFee: inboundFee,
3✔
7895
        }
3✔
7896

3✔
7897
        maxHtlc := lnwire.MilliSatoshi(req.MaxHtlcMsat)
3✔
7898
        var minHtlc *lnwire.MilliSatoshi
3✔
7899
        if req.MinHtlcMsatSpecified {
3✔
7900
                min := lnwire.MilliSatoshi(req.MinHtlcMsat)
×
7901
                minHtlc = &min
×
7902
        }
×
7903

7904
        chanPolicy := routing.ChannelPolicy{
3✔
7905
                FeeSchema:     feeSchema,
3✔
7906
                TimeLockDelta: req.TimeLockDelta,
3✔
7907
                MaxHTLC:       maxHtlc,
3✔
7908
                MinHTLC:       minHtlc,
3✔
7909
        }
3✔
7910

3✔
7911
        rpcsLog.Debugf("[updatechanpolicy] updating channel policy "+
3✔
7912
                "base_fee=%v, rate_fixed=%v, time_lock_delta: %v, "+
3✔
7913
                "min_htlc=%v, max_htlc=%v, targets=%v",
3✔
7914
                req.BaseFeeMsat, feeRateFixed, req.TimeLockDelta,
3✔
7915
                minHtlc, maxHtlc,
3✔
7916
                spew.Sdump(targetChans))
3✔
7917

3✔
7918
        // With the scope resolved, we'll now send this to the local channel
3✔
7919
        // manager so it can propagate the new policy for our target channel(s).
3✔
7920
        failedUpdates, err := r.server.localChanMgr.UpdatePolicy(chanPolicy,
3✔
7921
                req.CreateMissingEdge, targetChans...)
3✔
7922
        if err != nil {
3✔
7923
                return nil, err
×
7924
        }
×
7925

7926
        return &lnrpc.PolicyUpdateResponse{
3✔
7927
                FailedUpdates: failedUpdates,
3✔
7928
        }, nil
3✔
7929
}
7930

7931
// ForwardingHistory allows the caller to query the htlcswitch for a record of
7932
// all HTLC's forwarded within the target time range, and integer offset within
7933
// that time range. If no time-range is specified, then the first chunk of the
7934
// past 24 hrs of forwarding history are returned.
7935

7936
// A list of forwarding events are returned. The size of each forwarding event
7937
// is 40 bytes, and the max message size able to be returned in gRPC is 4 MiB.
7938
// In order to safely stay under this max limit, we'll return 50k events per
7939
// response.  Each response has the index offset of the last entry. The index
7940
// offset can be provided to the request to allow the caller to skip a series
7941
// of records.
7942
func (r *rpcServer) ForwardingHistory(ctx context.Context,
7943
        req *lnrpc.ForwardingHistoryRequest) (*lnrpc.ForwardingHistoryResponse,
7944
        error) {
3✔
7945

3✔
7946
        // Before we perform the queries below, we'll instruct the switch to
3✔
7947
        // flush any pending events to disk. This ensure we get a complete
3✔
7948
        // snapshot at this particular time.
3✔
7949
        if err := r.server.htlcSwitch.FlushForwardingEvents(); err != nil {
3✔
7950
                return nil, fmt.Errorf("unable to flush forwarding "+
×
7951
                        "events: %v", err)
×
7952
        }
×
7953

7954
        var (
3✔
7955
                startTime, endTime time.Time
3✔
7956

3✔
7957
                numEvents uint32
3✔
7958
        )
3✔
7959

3✔
7960
        // startTime defaults to the Unix epoch (0 unixtime, or
3✔
7961
        // midnight 01-01-1970).
3✔
7962
        startTime = time.Unix(int64(req.StartTime), 0)
3✔
7963

3✔
7964
        // If the end time wasn't specified, assume a default end time of now.
3✔
7965
        if req.EndTime == 0 {
6✔
7966
                now := time.Now()
3✔
7967
                endTime = now
3✔
7968
        } else {
3✔
7969
                endTime = time.Unix(int64(req.EndTime), 0)
×
7970
        }
×
7971

7972
        // If the number of events wasn't specified, then we'll default to
7973
        // returning the last 100 events.
7974
        numEvents = req.NumMaxEvents
3✔
7975
        if numEvents == 0 {
6✔
7976
                numEvents = 100
3✔
7977
        }
3✔
7978

7979
        // Next, we'll map the proto request into a format that is understood by
7980
        // the forwarding log.
7981
        eventQuery := channeldb.ForwardingEventQuery{
3✔
7982
                StartTime:    startTime,
3✔
7983
                EndTime:      endTime,
3✔
7984
                IndexOffset:  req.IndexOffset,
3✔
7985
                NumMaxEvents: numEvents,
3✔
7986
        }
3✔
7987
        timeSlice, err := r.server.miscDB.ForwardingLog().Query(eventQuery)
3✔
7988
        if err != nil {
3✔
7989
                return nil, fmt.Errorf("unable to query forwarding log: %w",
×
7990
                        err)
×
7991
        }
×
7992

7993
        // chanToPeerAlias caches previously looked up channel information.
7994
        chanToPeerAlias := make(map[lnwire.ShortChannelID]string)
3✔
7995

3✔
7996
        // Helper function to extract a peer's node alias given its SCID.
3✔
7997
        getRemoteAlias := func(chanID lnwire.ShortChannelID) (string, error) {
6✔
7998
                // If we'd previously seen this chanID then return the cached
3✔
7999
                // peer alias.
3✔
8000
                if peerAlias, ok := chanToPeerAlias[chanID]; ok {
6✔
8001
                        return peerAlias, nil
3✔
8002
                }
3✔
8003

8004
                // Else call the server to look up the peer alias.
8005
                edge, err := r.GetChanInfo(ctx, &lnrpc.ChanInfoRequest{
3✔
8006
                        ChanId: chanID.ToUint64(),
3✔
8007
                })
3✔
8008
                if err != nil {
3✔
8009
                        return "", err
×
8010
                }
×
8011

8012
                remotePub := edge.Node1Pub
3✔
8013
                if r.selfNode.String() == edge.Node1Pub {
5✔
8014
                        remotePub = edge.Node2Pub
2✔
8015
                }
2✔
8016

8017
                vertex, err := route.NewVertexFromStr(remotePub)
3✔
8018
                if err != nil {
3✔
8019
                        return "", err
×
8020
                }
×
8021

8022
                peer, err := r.server.graphDB.FetchLightningNode(vertex)
3✔
8023
                if err != nil {
3✔
8024
                        return "", err
×
8025
                }
×
8026

8027
                // Cache the peer alias.
8028
                chanToPeerAlias[chanID] = peer.Alias
3✔
8029

3✔
8030
                return peer.Alias, nil
3✔
8031
        }
8032

8033
        // TODO(roasbeef): add settlement latency?
8034
        //  * use FPE on all records?
8035

8036
        // With the events retrieved, we'll now map them into the proper proto
8037
        // response.
8038
        //
8039
        // TODO(roasbeef): show in ns for the outside?
8040
        fwdingEvents := make(
3✔
8041
                []*lnrpc.ForwardingEvent, len(timeSlice.ForwardingEvents),
3✔
8042
        )
3✔
8043
        resp := &lnrpc.ForwardingHistoryResponse{
3✔
8044
                ForwardingEvents: fwdingEvents,
3✔
8045
                LastOffsetIndex:  timeSlice.LastIndexOffset,
3✔
8046
        }
3✔
8047
        for i, event := range timeSlice.ForwardingEvents {
6✔
8048
                amtInMsat := event.AmtIn
3✔
8049
                amtOutMsat := event.AmtOut
3✔
8050
                feeMsat := event.AmtIn - event.AmtOut
3✔
8051

3✔
8052
                resp.ForwardingEvents[i] = &lnrpc.ForwardingEvent{
3✔
8053
                        Timestamp:   uint64(event.Timestamp.Unix()),
3✔
8054
                        TimestampNs: uint64(event.Timestamp.UnixNano()),
3✔
8055
                        ChanIdIn:    event.IncomingChanID.ToUint64(),
3✔
8056
                        ChanIdOut:   event.OutgoingChanID.ToUint64(),
3✔
8057
                        AmtIn:       uint64(amtInMsat.ToSatoshis()),
3✔
8058
                        AmtOut:      uint64(amtOutMsat.ToSatoshis()),
3✔
8059
                        Fee:         uint64(feeMsat.ToSatoshis()),
3✔
8060
                        FeeMsat:     uint64(feeMsat),
3✔
8061
                        AmtInMsat:   uint64(amtInMsat),
3✔
8062
                        AmtOutMsat:  uint64(amtOutMsat),
3✔
8063
                }
3✔
8064

3✔
8065
                if req.PeerAliasLookup {
6✔
8066
                        aliasIn, err := getRemoteAlias(event.IncomingChanID)
3✔
8067
                        if err != nil {
3✔
8068
                                aliasIn = fmt.Sprintf("unable to lookup peer "+
×
8069
                                        "alias: %v", err)
×
8070
                        }
×
8071
                        aliasOut, err := getRemoteAlias(event.OutgoingChanID)
3✔
8072
                        if err != nil {
3✔
8073
                                aliasOut = fmt.Sprintf("unable to lookup peer"+
×
8074
                                        "alias: %v", err)
×
8075
                        }
×
8076
                        resp.ForwardingEvents[i].PeerAliasIn = aliasIn
3✔
8077
                        resp.ForwardingEvents[i].PeerAliasOut = aliasOut
3✔
8078
                }
8079
        }
8080

8081
        return resp, nil
3✔
8082
}
8083

8084
// ExportChannelBackup attempts to return an encrypted static channel backup
8085
// for the target channel identified by it channel point. The backup is
8086
// encrypted with a key generated from the aezeed seed of the user. The
8087
// returned backup can either be restored using the RestoreChannelBackup method
8088
// once lnd is running, or via the InitWallet and UnlockWallet methods from the
8089
// WalletUnlocker service.
8090
func (r *rpcServer) ExportChannelBackup(ctx context.Context,
8091
        in *lnrpc.ExportChannelBackupRequest) (*lnrpc.ChannelBackup, error) {
3✔
8092

3✔
8093
        // First, we'll convert the lnrpc channel point into a wire.OutPoint
3✔
8094
        // that we can manipulate.
3✔
8095
        txid, err := lnrpc.GetChanPointFundingTxid(in.ChanPoint)
3✔
8096
        if err != nil {
3✔
8097
                return nil, err
×
8098
        }
×
8099
        chanPoint := wire.OutPoint{
3✔
8100
                Hash:  *txid,
3✔
8101
                Index: in.ChanPoint.OutputIndex,
3✔
8102
        }
3✔
8103

3✔
8104
        // Next, we'll attempt to fetch a channel backup for this channel from
3✔
8105
        // the database. If this channel has been closed, or the outpoint is
3✔
8106
        // unknown, then we'll return an error
3✔
8107
        unpackedBackup, err := chanbackup.FetchBackupForChan(
3✔
8108
                chanPoint, r.server.chanStateDB, r.server.addrSource,
3✔
8109
        )
3✔
8110
        if err != nil {
3✔
8111
                return nil, err
×
8112
        }
×
8113

8114
        // At this point, we have an unpacked backup (plaintext) so we'll now
8115
        // attempt to serialize and encrypt it in order to create a packed
8116
        // backup.
8117
        packedBackups, err := chanbackup.PackStaticChanBackups(
3✔
8118
                []chanbackup.Single{*unpackedBackup},
3✔
8119
                r.server.cc.KeyRing,
3✔
8120
        )
3✔
8121
        if err != nil {
3✔
8122
                return nil, fmt.Errorf("packing of back ups failed: %w", err)
×
8123
        }
×
8124

8125
        // Before we proceed, we'll ensure that we received a backup for this
8126
        // channel, otherwise, we'll bail out.
8127
        packedBackup, ok := packedBackups[chanPoint]
3✔
8128
        if !ok {
3✔
8129
                return nil, fmt.Errorf("expected single backup for "+
×
8130
                        "ChannelPoint(%v), got %v", chanPoint,
×
8131
                        len(packedBackup))
×
8132
        }
×
8133

8134
        return &lnrpc.ChannelBackup{
3✔
8135
                ChanPoint:  in.ChanPoint,
3✔
8136
                ChanBackup: packedBackup,
3✔
8137
        }, nil
3✔
8138
}
8139

8140
// VerifyChanBackup allows a caller to verify the integrity of a channel backup
8141
// snapshot. This method will accept both either a packed Single or a packed
8142
// Multi. Specifying both will result in an error.
8143
func (r *rpcServer) VerifyChanBackup(ctx context.Context,
8144
        in *lnrpc.ChanBackupSnapshot) (*lnrpc.VerifyChanBackupResponse, error) {
3✔
8145

3✔
8146
        var (
3✔
8147
                channels []chanbackup.Single
3✔
8148
                err      error
3✔
8149
        )
3✔
8150
        switch {
3✔
8151
        // If neither a Single or Multi has been specified, then we have nothing
8152
        // to verify.
8153
        case in.GetSingleChanBackups() == nil && in.GetMultiChanBackup() == nil:
×
8154
                return nil, errors.New("either a Single or Multi channel " +
×
8155
                        "backup must be specified")
×
8156

8157
        // Either a Single or a Multi must be specified, but not both.
8158
        case in.GetSingleChanBackups() != nil && in.GetMultiChanBackup() != nil:
×
8159
                return nil, errors.New("either a Single or Multi channel " +
×
8160
                        "backup must be specified, but not both")
×
8161

8162
        // If a Single is specified then we'll only accept one of them to allow
8163
        // the caller to map the valid/invalid state for each individual Single.
8164
        case in.GetSingleChanBackups() != nil:
×
8165
                chanBackupsProtos := in.GetSingleChanBackups().ChanBackups
×
8166
                if len(chanBackupsProtos) != 1 {
×
8167
                        return nil, errors.New("only one Single is accepted " +
×
8168
                                "at a time")
×
8169
                }
×
8170

8171
                // First, we'll convert the raw byte slice into a type we can
8172
                // work with a bit better.
8173
                chanBackup := chanbackup.PackedSingles(
×
8174
                        [][]byte{chanBackupsProtos[0].ChanBackup},
×
8175
                )
×
8176

×
8177
                // With our PackedSingles created, we'll attempt to unpack the
×
8178
                // backup. If this fails, then we know the backup is invalid for
×
8179
                // some reason.
×
8180
                channels, err = chanBackup.Unpack(r.server.cc.KeyRing)
×
8181
                if err != nil {
×
8182
                        return nil, fmt.Errorf("invalid single channel "+
×
8183
                                "backup: %v", err)
×
8184
                }
×
8185

8186
        case in.GetMultiChanBackup() != nil:
3✔
8187
                // We'll convert the raw byte slice into a PackedMulti that we
3✔
8188
                // can easily work with.
3✔
8189
                packedMultiBackup := in.GetMultiChanBackup().MultiChanBackup
3✔
8190
                packedMulti := chanbackup.PackedMulti(packedMultiBackup)
3✔
8191

3✔
8192
                // We'll now attempt to unpack the Multi. If this fails, then we
3✔
8193
                // know it's invalid.
3✔
8194
                multi, err := packedMulti.Unpack(r.server.cc.KeyRing)
3✔
8195
                if err != nil {
3✔
8196
                        return nil, fmt.Errorf("invalid multi channel backup: "+
×
8197
                                "%v", err)
×
8198
                }
×
8199

8200
                channels = multi.StaticBackups
3✔
8201
        }
8202

8203
        return &lnrpc.VerifyChanBackupResponse{
3✔
8204
                ChanPoints: fn.Map(channels, func(c chanbackup.Single) string {
6✔
8205
                        return c.FundingOutpoint.String()
3✔
8206
                }),
3✔
8207
        }, nil
8208
}
8209

8210
// createBackupSnapshot converts the passed Single backup into a snapshot which
8211
// contains individual packed single backups, as well as a single packed multi
8212
// backup.
8213
func (r *rpcServer) createBackupSnapshot(backups []chanbackup.Single) (
8214
        *lnrpc.ChanBackupSnapshot, error) {
3✔
8215

3✔
8216
        // Once we have the set of back ups, we'll attempt to pack them all
3✔
8217
        // into a series of single channel backups.
3✔
8218
        singleChanPackedBackups, err := chanbackup.PackStaticChanBackups(
3✔
8219
                backups, r.server.cc.KeyRing,
3✔
8220
        )
3✔
8221
        if err != nil {
3✔
8222
                return nil, fmt.Errorf("unable to pack set of chan "+
×
8223
                        "backups: %v", err)
×
8224
        }
×
8225

8226
        // Now that we have our set of single packed backups, we'll morph that
8227
        // into a form that the proto response requires.
8228
        numBackups := len(singleChanPackedBackups)
3✔
8229
        singleBackupResp := &lnrpc.ChannelBackups{
3✔
8230
                ChanBackups: make([]*lnrpc.ChannelBackup, 0, numBackups),
3✔
8231
        }
3✔
8232
        for chanPoint, singlePackedBackup := range singleChanPackedBackups {
6✔
8233
                txid := chanPoint.Hash
3✔
8234
                rpcChanPoint := &lnrpc.ChannelPoint{
3✔
8235
                        FundingTxid: &lnrpc.ChannelPoint_FundingTxidBytes{
3✔
8236
                                FundingTxidBytes: txid[:],
3✔
8237
                        },
3✔
8238
                        OutputIndex: chanPoint.Index,
3✔
8239
                }
3✔
8240

3✔
8241
                singleBackupResp.ChanBackups = append(
3✔
8242
                        singleBackupResp.ChanBackups,
3✔
8243
                        &lnrpc.ChannelBackup{
3✔
8244
                                ChanPoint:  rpcChanPoint,
3✔
8245
                                ChanBackup: singlePackedBackup,
3✔
8246
                        },
3✔
8247
                )
3✔
8248
        }
3✔
8249

8250
        // In addition, to the set of single chan backups, we'll also create a
8251
        // single multi-channel backup which can be serialized into a single
8252
        // file for safe storage.
8253
        var b bytes.Buffer
3✔
8254
        unpackedMultiBackup := chanbackup.Multi{
3✔
8255
                StaticBackups: backups,
3✔
8256
        }
3✔
8257
        err = unpackedMultiBackup.PackToWriter(&b, r.server.cc.KeyRing)
3✔
8258
        if err != nil {
3✔
8259
                return nil, fmt.Errorf("unable to multi-pack backups: %w", err)
×
8260
        }
×
8261

8262
        multiBackupResp := &lnrpc.MultiChanBackup{
3✔
8263
                MultiChanBackup: b.Bytes(),
3✔
8264
        }
3✔
8265
        for _, singleBackup := range singleBackupResp.ChanBackups {
6✔
8266
                multiBackupResp.ChanPoints = append(
3✔
8267
                        multiBackupResp.ChanPoints, singleBackup.ChanPoint,
3✔
8268
                )
3✔
8269
        }
3✔
8270

8271
        return &lnrpc.ChanBackupSnapshot{
3✔
8272
                SingleChanBackups: singleBackupResp,
3✔
8273
                MultiChanBackup:   multiBackupResp,
3✔
8274
        }, nil
3✔
8275
}
8276

8277
// ExportAllChannelBackups returns static channel backups for all existing
8278
// channels known to lnd. A set of regular singular static channel backups for
8279
// each channel are returned. Additionally, a multi-channel backup is returned
8280
// as well, which contains a single encrypted blob containing the backups of
8281
// each channel.
8282
func (r *rpcServer) ExportAllChannelBackups(ctx context.Context,
8283
        in *lnrpc.ChanBackupExportRequest) (*lnrpc.ChanBackupSnapshot, error) {
3✔
8284

3✔
8285
        // First, we'll attempt to read back ups for ALL currently opened
3✔
8286
        // channels from disk.
3✔
8287
        allUnpackedBackups, err := chanbackup.FetchStaticChanBackups(
3✔
8288
                r.server.chanStateDB, r.server.addrSource,
3✔
8289
        )
3✔
8290
        if err != nil {
3✔
8291
                return nil, fmt.Errorf("unable to fetch all static chan "+
×
8292
                        "backups: %v", err)
×
8293
        }
×
8294

8295
        // With the backups assembled, we'll create a full snapshot.
8296
        return r.createBackupSnapshot(allUnpackedBackups)
3✔
8297
}
8298

8299
// RestoreChannelBackups accepts a set of singular channel backups, or a single
8300
// encrypted multi-chan backup and attempts to recover any funds remaining
8301
// within the channel. If we're able to unpack the backup, then the new channel
8302
// will be shown under listchannels, as well as pending channels.
8303
func (r *rpcServer) RestoreChannelBackups(ctx context.Context,
8304
        in *lnrpc.RestoreChanBackupRequest) (*lnrpc.RestoreBackupResponse, error) {
3✔
8305

3✔
8306
        // The server hasn't yet started, so it won't be able to service any of
3✔
8307
        // our requests, so we'll bail early here.
3✔
8308
        if !r.server.Started() {
3✔
8309
                return nil, ErrServerNotActive
×
8310
        }
×
8311

8312
        // First, we'll make our implementation of the
8313
        // chanbackup.ChannelRestorer interface which we'll use to properly
8314
        // restore either a set of chanbackup.Single or chanbackup.Multi
8315
        // backups.
8316
        chanRestorer := &chanDBRestorer{
3✔
8317
                db:         r.server.chanStateDB,
3✔
8318
                secretKeys: r.server.cc.KeyRing,
3✔
8319
                chainArb:   r.server.chainArb,
3✔
8320
        }
3✔
8321

3✔
8322
        // We'll accept either a list of Single backups, or a single Multi
3✔
8323
        // backup which contains several single backups.
3✔
8324
        var (
3✔
8325
                numRestored int
3✔
8326
                err         error
3✔
8327
        )
3✔
8328
        switch {
3✔
8329
        case in.GetChanBackups() != nil:
×
8330
                chanBackupsProtos := in.GetChanBackups()
×
8331

×
8332
                // Now that we know what type of backup we're working with,
×
8333
                // we'll parse them all out into a more suitable format.
×
8334
                packedBackups := make([][]byte, 0, len(chanBackupsProtos.ChanBackups))
×
8335
                for _, chanBackup := range chanBackupsProtos.ChanBackups {
×
8336
                        packedBackups = append(
×
8337
                                packedBackups, chanBackup.ChanBackup,
×
8338
                        )
×
8339
                }
×
8340

8341
                // With our backups obtained, we'll now restore them which will
8342
                // write the new backups to disk, and then attempt to connect
8343
                // out to any peers that we know of which were our prior
8344
                // channel peers.
8345
                numRestored, err = chanbackup.UnpackAndRecoverSingles(
×
8346
                        chanbackup.PackedSingles(packedBackups),
×
8347
                        r.server.cc.KeyRing, chanRestorer, r.server,
×
8348
                )
×
8349
                if err != nil {
×
8350
                        return nil, fmt.Errorf("unable to unpack single "+
×
8351
                                "backups: %v", err)
×
8352
                }
×
8353

8354
        case in.GetMultiChanBackup() != nil:
3✔
8355
                packedMultiBackup := in.GetMultiChanBackup()
3✔
8356

3✔
8357
                // With our backups obtained, we'll now restore them which will
3✔
8358
                // write the new backups to disk, and then attempt to connect
3✔
8359
                // out to any peers that we know of which were our prior
3✔
8360
                // channel peers.
3✔
8361
                packedMulti := chanbackup.PackedMulti(packedMultiBackup)
3✔
8362
                numRestored, err = chanbackup.UnpackAndRecoverMulti(
3✔
8363
                        packedMulti, r.server.cc.KeyRing, chanRestorer,
3✔
8364
                        r.server,
3✔
8365
                )
3✔
8366
                if err != nil {
3✔
8367
                        return nil, fmt.Errorf("unable to unpack chan "+
×
8368
                                "backup: %v", err)
×
8369
                }
×
8370
        }
8371

8372
        return &lnrpc.RestoreBackupResponse{
3✔
8373
                NumRestored: uint32(numRestored),
3✔
8374
        }, nil
3✔
8375
}
8376

8377
// SubscribeChannelBackups allows a client to sub-subscribe to the most up to
8378
// date information concerning the state of all channel back ups. Each time a
8379
// new channel is added, we return the new set of channels, along with a
8380
// multi-chan backup containing the backup info for all channels. Each time a
8381
// channel is closed, we send a new update, which contains new new chan back
8382
// ups, but the updated set of encrypted multi-chan backups with the closed
8383
// channel(s) removed.
8384
func (r *rpcServer) SubscribeChannelBackups(req *lnrpc.ChannelBackupSubscription,
8385
        updateStream lnrpc.Lightning_SubscribeChannelBackupsServer) error {
3✔
8386

3✔
8387
        // First, we'll subscribe to the primary channel notifier so we can
3✔
8388
        // obtain events for new pending/opened/closed channels.
3✔
8389
        chanSubscription, err := r.server.channelNotifier.SubscribeChannelEvents()
3✔
8390
        if err != nil {
3✔
8391
                return err
×
8392
        }
×
8393

8394
        defer chanSubscription.Cancel()
3✔
8395
        for {
6✔
8396
                select {
3✔
8397
                // A new event has been sent by the channel notifier, we'll
8398
                // assemble, then sling out a new event to the client.
8399
                case e := <-chanSubscription.Updates():
3✔
8400
                        // TODO(roasbeef): batch dispatch ntnfs
3✔
8401

3✔
8402
                        switch e.(type) {
3✔
8403

8404
                        // We only care about new/closed channels, so we'll
8405
                        // skip any events for active/inactive channels.
8406
                        // To make the subscription behave the same way as the
8407
                        // synchronous call and the file based backup, we also
8408
                        // include pending channels in the update.
8409
                        case channelnotifier.ActiveChannelEvent:
3✔
8410
                                continue
3✔
8411
                        case channelnotifier.InactiveChannelEvent:
3✔
8412
                                continue
3✔
8413
                        case channelnotifier.ActiveLinkEvent:
3✔
8414
                                continue
3✔
8415
                        case channelnotifier.InactiveLinkEvent:
3✔
8416
                                continue
3✔
8417
                        }
8418

8419
                        // Now that we know the channel state has changed,
8420
                        // we'll obtains the current set of single channel
8421
                        // backups from disk.
8422
                        chanBackups, err := chanbackup.FetchStaticChanBackups(
3✔
8423
                                r.server.chanStateDB, r.server.addrSource,
3✔
8424
                        )
3✔
8425
                        if err != nil {
3✔
8426
                                return fmt.Errorf("unable to fetch all "+
×
8427
                                        "static chan backups: %v", err)
×
8428
                        }
×
8429

8430
                        // With our backups obtained, we'll pack them into a
8431
                        // snapshot and send them back to the client.
8432
                        backupSnapshot, err := r.createBackupSnapshot(
3✔
8433
                                chanBackups,
3✔
8434
                        )
3✔
8435
                        if err != nil {
3✔
8436
                                return err
×
8437
                        }
×
8438
                        err = updateStream.Send(backupSnapshot)
3✔
8439
                        if err != nil {
3✔
8440
                                return err
×
8441
                        }
×
8442

8443
                // The response stream's context for whatever reason has been
8444
                // closed. If context is closed by an exceeded deadline we will
8445
                // return an error.
8446
                case <-updateStream.Context().Done():
3✔
8447
                        if errors.Is(updateStream.Context().Err(), context.Canceled) {
6✔
8448
                                return nil
3✔
8449
                        }
3✔
8450
                        return updateStream.Context().Err()
×
8451

8452
                case <-r.quit:
×
8453
                        return nil
×
8454
                }
8455
        }
8456
}
8457

8458
// ChannelAcceptor dispatches a bi-directional streaming RPC in which
8459
// OpenChannel requests are sent to the client and the client responds with
8460
// a boolean that tells LND whether or not to accept the channel. This allows
8461
// node operators to specify their own criteria for accepting inbound channels
8462
// through a single persistent connection.
8463
func (r *rpcServer) ChannelAcceptor(stream lnrpc.Lightning_ChannelAcceptorServer) error {
3✔
8464
        chainedAcceptor := r.chanPredicate
3✔
8465

3✔
8466
        // Create a new RPCAcceptor which will send requests into the
3✔
8467
        // newRequests channel when it receives them.
3✔
8468
        rpcAcceptor := chanacceptor.NewRPCAcceptor(
3✔
8469
                stream.Recv, stream.Send, r.cfg.AcceptorTimeout,
3✔
8470
                r.cfg.ActiveNetParams.Params, r.quit,
3✔
8471
        )
3✔
8472

3✔
8473
        // Add the RPCAcceptor to the ChainedAcceptor and defer its removal.
3✔
8474
        id := chainedAcceptor.AddAcceptor(rpcAcceptor)
3✔
8475
        defer chainedAcceptor.RemoveAcceptor(id)
3✔
8476

3✔
8477
        // Run the rpc acceptor, which will accept requests for channel
3✔
8478
        // acceptance decisions from our chained acceptor, send them to the
3✔
8479
        // channel acceptor and listen for and report responses. This function
3✔
8480
        // blocks, and will exit if the rpcserver receives the instruction to
3✔
8481
        // shutdown, or the client cancels.
3✔
8482
        return rpcAcceptor.Run()
3✔
8483
}
3✔
8484

8485
// BakeMacaroon allows the creation of a new macaroon with custom read and write
8486
// permissions. No first-party caveats are added since this can be done offline.
8487
// If the --allow-external-permissions flag is set, the RPC will allow
8488
// external permissions that LND is not aware of.
8489
func (r *rpcServer) BakeMacaroon(ctx context.Context,
8490
        req *lnrpc.BakeMacaroonRequest) (*lnrpc.BakeMacaroonResponse, error) {
3✔
8491

3✔
8492
        // If the --no-macaroons flag is used to start lnd, the macaroon service
3✔
8493
        // is not initialized. Therefore we can't bake new macaroons.
3✔
8494
        if r.macService == nil {
3✔
8495
                return nil, errMacaroonDisabled
×
8496
        }
×
8497

8498
        helpMsg := fmt.Sprintf("supported actions are %v, supported entities "+
3✔
8499
                "are %v", validActions, validEntities)
3✔
8500

3✔
8501
        // Don't allow empty permission list as it doesn't make sense to have
3✔
8502
        // a macaroon that is not allowed to access any RPC.
3✔
8503
        if len(req.Permissions) == 0 {
6✔
8504
                return nil, fmt.Errorf("permission list cannot be empty. "+
3✔
8505
                        "specify at least one action/entity pair. %s", helpMsg)
3✔
8506
        }
3✔
8507

8508
        // Validate and map permission struct used by gRPC to the one used by
8509
        // the bakery. If the --allow-external-permissions flag is set, we
8510
        // will not validate, but map.
8511
        requestedPermissions := make([]bakery.Op, len(req.Permissions))
3✔
8512
        for idx, op := range req.Permissions {
6✔
8513
                if req.AllowExternalPermissions {
6✔
8514
                        requestedPermissions[idx] = bakery.Op{
3✔
8515
                                Entity: op.Entity,
3✔
8516
                                Action: op.Action,
3✔
8517
                        }
3✔
8518
                        continue
3✔
8519
                }
8520

8521
                if !stringInSlice(op.Entity, validEntities) {
6✔
8522
                        return nil, fmt.Errorf("invalid permission entity. %s",
3✔
8523
                                helpMsg)
3✔
8524
                }
3✔
8525

8526
                // Either we have the special entity "uri" which specifies a
8527
                // full gRPC URI or we have one of the pre-defined actions.
8528
                if op.Entity == macaroons.PermissionEntityCustomURI {
6✔
8529
                        allPermissions := r.interceptorChain.Permissions()
3✔
8530
                        _, ok := allPermissions[op.Action]
3✔
8531
                        if !ok {
3✔
8532
                                return nil, fmt.Errorf("invalid permission " +
×
8533
                                        "action, must be an existing URI in " +
×
8534
                                        "the format /package.Service/" +
×
8535
                                        "MethodName")
×
8536
                        }
×
8537
                } else if !stringInSlice(op.Action, validActions) {
6✔
8538
                        return nil, fmt.Errorf("invalid permission action. %s",
3✔
8539
                                helpMsg)
3✔
8540
                }
3✔
8541

8542
                requestedPermissions[idx] = bakery.Op{
3✔
8543
                        Entity: op.Entity,
3✔
8544
                        Action: op.Action,
3✔
8545
                }
3✔
8546
        }
8547

8548
        // Convert root key id from uint64 to bytes. Because the
8549
        // DefaultRootKeyID is a digit 0 expressed in a byte slice of a string
8550
        // "0", we will keep the IDs in the same format - all must be numeric,
8551
        // and must be a byte slice of string value of the digit, e.g.,
8552
        // uint64(123) to string(123).
8553
        rootKeyID := []byte(strconv.FormatUint(req.RootKeyId, 10))
3✔
8554

3✔
8555
        // Bake new macaroon with the given permissions and send it binary
3✔
8556
        // serialized and hex encoded to the client.
3✔
8557
        newMac, err := r.macService.NewMacaroon(
3✔
8558
                ctx, rootKeyID, requestedPermissions...,
3✔
8559
        )
3✔
8560
        if err != nil {
3✔
8561
                return nil, err
×
8562
        }
×
8563
        newMacBytes, err := newMac.M().MarshalBinary()
3✔
8564
        if err != nil {
3✔
8565
                return nil, err
×
8566
        }
×
8567
        resp := &lnrpc.BakeMacaroonResponse{}
3✔
8568
        resp.Macaroon = hex.EncodeToString(newMacBytes)
3✔
8569

3✔
8570
        return resp, nil
3✔
8571
}
8572

8573
// ListMacaroonIDs returns a list of macaroon root key IDs in use.
8574
func (r *rpcServer) ListMacaroonIDs(ctx context.Context,
8575
        req *lnrpc.ListMacaroonIDsRequest) (
8576
        *lnrpc.ListMacaroonIDsResponse, error) {
3✔
8577

3✔
8578
        // If the --no-macaroons flag is used to start lnd, the macaroon service
3✔
8579
        // is not initialized. Therefore we can't show any IDs.
3✔
8580
        if r.macService == nil {
3✔
8581
                return nil, errMacaroonDisabled
×
8582
        }
×
8583

8584
        rootKeyIDByteSlice, err := r.macService.ListMacaroonIDs(ctx)
3✔
8585
        if err != nil {
3✔
8586
                return nil, err
×
8587
        }
×
8588

8589
        var rootKeyIDs []uint64
3✔
8590
        for _, value := range rootKeyIDByteSlice {
6✔
8591
                // Convert bytes into uint64.
3✔
8592
                id, err := strconv.ParseUint(string(value), 10, 64)
3✔
8593
                if err != nil {
3✔
8594
                        return nil, err
×
8595
                }
×
8596

8597
                rootKeyIDs = append(rootKeyIDs, id)
3✔
8598
        }
8599

8600
        return &lnrpc.ListMacaroonIDsResponse{RootKeyIds: rootKeyIDs}, nil
3✔
8601
}
8602

8603
// DeleteMacaroonID removes a specific macaroon ID.
8604
func (r *rpcServer) DeleteMacaroonID(ctx context.Context,
8605
        req *lnrpc.DeleteMacaroonIDRequest) (
8606
        *lnrpc.DeleteMacaroonIDResponse, error) {
3✔
8607

3✔
8608
        // If the --no-macaroons flag is used to start lnd, the macaroon service
3✔
8609
        // is not initialized. Therefore we can't delete any IDs.
3✔
8610
        if r.macService == nil {
3✔
8611
                return nil, errMacaroonDisabled
×
8612
        }
×
8613

8614
        // Convert root key id from uint64 to bytes. Because the
8615
        // DefaultRootKeyID is a digit 0 expressed in a byte slice of a string
8616
        // "0", we will keep the IDs in the same format - all must be digit, and
8617
        // must be a byte slice of string value of the digit.
8618
        rootKeyID := []byte(strconv.FormatUint(req.RootKeyId, 10))
3✔
8619
        deletedIDBytes, err := r.macService.DeleteMacaroonID(ctx, rootKeyID)
3✔
8620
        if err != nil {
6✔
8621
                return nil, err
3✔
8622
        }
3✔
8623

8624
        return &lnrpc.DeleteMacaroonIDResponse{
3✔
8625
                // If the root key ID doesn't exist, it won't be deleted. We
3✔
8626
                // will return a response with deleted = false, otherwise true.
3✔
8627
                Deleted: deletedIDBytes != nil,
3✔
8628
        }, nil
3✔
8629
}
8630

8631
// ListPermissions lists all RPC method URIs and their required macaroon
8632
// permissions to access them.
8633
func (r *rpcServer) ListPermissions(_ context.Context,
8634
        _ *lnrpc.ListPermissionsRequest) (*lnrpc.ListPermissionsResponse,
8635
        error) {
3✔
8636

3✔
8637
        permissionMap := make(map[string]*lnrpc.MacaroonPermissionList)
3✔
8638
        for uri, perms := range r.interceptorChain.Permissions() {
6✔
8639
                rpcPerms := make([]*lnrpc.MacaroonPermission, len(perms))
3✔
8640
                for idx, perm := range perms {
6✔
8641
                        rpcPerms[idx] = &lnrpc.MacaroonPermission{
3✔
8642
                                Entity: perm.Entity,
3✔
8643
                                Action: perm.Action,
3✔
8644
                        }
3✔
8645
                }
3✔
8646
                permissionMap[uri] = &lnrpc.MacaroonPermissionList{
3✔
8647
                        Permissions: rpcPerms,
3✔
8648
                }
3✔
8649
        }
8650

8651
        return &lnrpc.ListPermissionsResponse{
3✔
8652
                MethodPermissions: permissionMap,
3✔
8653
        }, nil
3✔
8654
}
8655

8656
// CheckMacaroonPermissions checks the caveats and permissions of a macaroon.
8657
func (r *rpcServer) CheckMacaroonPermissions(ctx context.Context,
8658
        req *lnrpc.CheckMacPermRequest) (*lnrpc.CheckMacPermResponse, error) {
3✔
8659

3✔
8660
        // Turn grpc macaroon permission into bakery.Op for the server to
3✔
8661
        // process.
3✔
8662
        permissions := make([]bakery.Op, len(req.Permissions))
3✔
8663
        for idx, perm := range req.Permissions {
6✔
8664
                permissions[idx] = bakery.Op{
3✔
8665
                        Entity: perm.Entity,
3✔
8666
                        Action: perm.Action,
3✔
8667
                }
3✔
8668
        }
3✔
8669

8670
        err := r.macService.CheckMacAuth(
3✔
8671
                ctx, req.Macaroon, permissions, req.FullMethod,
3✔
8672
        )
3✔
8673
        if err != nil {
6✔
8674
                return nil, status.Error(codes.InvalidArgument, err.Error())
3✔
8675
        }
3✔
8676

8677
        return &lnrpc.CheckMacPermResponse{
3✔
8678
                Valid: true,
3✔
8679
        }, nil
3✔
8680
}
8681

8682
// FundingStateStep is an advanced funding related call that allows the caller
8683
// to either execute some preparatory steps for a funding workflow, or manually
8684
// progress a funding workflow. The primary way a funding flow is identified is
8685
// via its pending channel ID. As an example, this method can be used to
8686
// specify that we're expecting a funding flow for a particular pending channel
8687
// ID, for which we need to use specific parameters.  Alternatively, this can
8688
// be used to interactively drive PSBT signing for funding for partially
8689
// complete funding transactions.
8690
func (r *rpcServer) FundingStateStep(ctx context.Context,
8691
        in *lnrpc.FundingTransitionMsg) (*lnrpc.FundingStateStepResp, error) {
3✔
8692

3✔
8693
        var pendingChanID [32]byte
3✔
8694
        switch {
3✔
8695
        // If this is a message to register a new shim that is an external
8696
        // channel point, then we'll contact the wallet to register this new
8697
        // shim. A user will use this method to register a new channel funding
8698
        // workflow which has already been partially negotiated outside of the
8699
        // core protocol.
8700
        case in.GetShimRegister() != nil &&
8701
                in.GetShimRegister().GetChanPointShim() != nil:
3✔
8702

3✔
8703
                rpcShimIntent := in.GetShimRegister().GetChanPointShim()
3✔
8704

3✔
8705
                // Using the rpc shim as a template, we'll construct a new
3✔
8706
                // chanfunding.Assembler that is able to express proper
3✔
8707
                // formulation of this expected channel.
3✔
8708
                shimAssembler, err := newFundingShimAssembler(
3✔
8709
                        rpcShimIntent, false, r.server.cc.KeyRing,
3✔
8710
                )
3✔
8711
                if err != nil {
3✔
8712
                        return nil, err
×
8713
                }
×
8714
                req := &chanfunding.Request{
3✔
8715
                        RemoteAmt: btcutil.Amount(rpcShimIntent.Amt),
3✔
8716
                }
3✔
8717
                shimIntent, err := shimAssembler.ProvisionChannel(req)
3✔
8718
                if err != nil {
3✔
8719
                        return nil, err
×
8720
                }
×
8721

8722
                // Once we have the intent, we'll register it with the wallet.
8723
                // Once we receive an incoming funding request that uses this
8724
                // pending channel ID, then this shim will be dispatched in
8725
                // place of our regular funding workflow.
8726
                copy(pendingChanID[:], rpcShimIntent.PendingChanId)
3✔
8727
                err = r.server.cc.Wallet.RegisterFundingIntent(
3✔
8728
                        pendingChanID, shimIntent,
3✔
8729
                )
3✔
8730
                if err != nil {
6✔
8731
                        return nil, err
3✔
8732
                }
3✔
8733

8734
        // There is no need to register a PSBT shim before opening the channel,
8735
        // even though our RPC message structure allows for it. Inform the user
8736
        // by returning a proper error instead of just doing nothing.
8737
        case in.GetShimRegister() != nil &&
8738
                in.GetShimRegister().GetPsbtShim() != nil:
×
8739

×
8740
                return nil, fmt.Errorf("PSBT shim must only be sent when " +
×
8741
                        "opening a channel")
×
8742

8743
        // If this is a transition to cancel an existing shim, then we'll pass
8744
        // this message along to the wallet, informing it that the intent no
8745
        // longer needs to be considered and should be cleaned up.
8746
        case in.GetShimCancel() != nil:
×
8747
                rpcsLog.Debugf("Canceling funding shim for pending_id=%x",
×
8748
                        in.GetShimCancel().PendingChanId)
×
8749

×
8750
                copy(pendingChanID[:], in.GetShimCancel().PendingChanId)
×
8751
                err := r.server.cc.Wallet.CancelFundingIntent(pendingChanID)
×
8752
                if err != nil {
×
8753
                        return nil, err
×
8754
                }
×
8755

8756
        // If this is a transition to verify the PSBT for an existing shim,
8757
        // we'll do so and then store the verified PSBT for later so we can
8758
        // compare it to the final, signed one.
8759
        case in.GetPsbtVerify() != nil:
3✔
8760
                rpcsLog.Debugf("Verifying PSBT for pending_id=%x",
3✔
8761
                        in.GetPsbtVerify().PendingChanId)
3✔
8762

3✔
8763
                copy(pendingChanID[:], in.GetPsbtVerify().PendingChanId)
3✔
8764
                packet, err := psbt.NewFromRawBytes(
3✔
8765
                        bytes.NewReader(in.GetPsbtVerify().FundedPsbt), false,
3✔
8766
                )
3✔
8767
                if err != nil {
3✔
8768
                        return nil, fmt.Errorf("error parsing psbt: %w", err)
×
8769
                }
×
8770

8771
                err = r.server.cc.Wallet.PsbtFundingVerify(
3✔
8772
                        pendingChanID, packet, in.GetPsbtVerify().SkipFinalize,
3✔
8773
                )
3✔
8774
                if err != nil {
3✔
8775
                        return nil, err
×
8776
                }
×
8777

8778
        // If this is a transition to finalize the PSBT funding flow, we compare
8779
        // the final PSBT to the previously verified one and if nothing
8780
        // unexpected was changed, continue the channel opening process.
8781
        case in.GetPsbtFinalize() != nil:
3✔
8782
                msg := in.GetPsbtFinalize()
3✔
8783
                rpcsLog.Debugf("Finalizing PSBT for pending_id=%x",
3✔
8784
                        msg.PendingChanId)
3✔
8785

3✔
8786
                copy(pendingChanID[:], in.GetPsbtFinalize().PendingChanId)
3✔
8787

3✔
8788
                var (
3✔
8789
                        packet *psbt.Packet
3✔
8790
                        rawTx  *wire.MsgTx
3✔
8791
                        err    error
3✔
8792
                )
3✔
8793

3✔
8794
                // Either the signed PSBT or the raw transaction need to be set
3✔
8795
                // but not both at the same time.
3✔
8796
                switch {
3✔
8797
                case len(msg.SignedPsbt) > 0 && len(msg.FinalRawTx) > 0:
×
8798
                        return nil, fmt.Errorf("cannot set both signed PSBT " +
×
8799
                                "and final raw TX at the same time")
×
8800

8801
                case len(msg.SignedPsbt) > 0:
3✔
8802
                        packet, err = psbt.NewFromRawBytes(
3✔
8803
                                bytes.NewReader(in.GetPsbtFinalize().SignedPsbt),
3✔
8804
                                false,
3✔
8805
                        )
3✔
8806
                        if err != nil {
3✔
8807
                                return nil, fmt.Errorf("error parsing psbt: %w",
×
8808
                                        err)
×
8809
                        }
×
8810

8811
                case len(msg.FinalRawTx) > 0:
3✔
8812
                        rawTx = &wire.MsgTx{}
3✔
8813
                        err = rawTx.Deserialize(bytes.NewReader(msg.FinalRawTx))
3✔
8814
                        if err != nil {
3✔
8815
                                return nil, fmt.Errorf("error parsing final "+
×
8816
                                        "raw TX: %v", err)
×
8817
                        }
×
8818

8819
                default:
×
8820
                        return nil, fmt.Errorf("PSBT or raw transaction to " +
×
8821
                                "finalize missing")
×
8822
                }
8823

8824
                err = r.server.cc.Wallet.PsbtFundingFinalize(
3✔
8825
                        pendingChanID, packet, rawTx,
3✔
8826
                )
3✔
8827
                if err != nil {
3✔
8828
                        return nil, err
×
8829
                }
×
8830
        }
8831

8832
        // TODO(roasbeef): extend PendingChannels to also show shims
8833

8834
        // TODO(roasbeef): return resulting state? also add a method to query
8835
        // current state?
8836
        return &lnrpc.FundingStateStepResp{}, nil
3✔
8837
}
8838

8839
// RegisterRPCMiddleware adds a new gRPC middleware to the interceptor chain. A
8840
// gRPC middleware is software component external to lnd that aims to add
8841
// additional business logic to lnd by observing/intercepting/validating
8842
// incoming gRPC client requests and (if needed) replacing/overwriting outgoing
8843
// messages before they're sent to the client. When registering the middleware
8844
// must identify itself and indicate what custom macaroon caveats it wants to
8845
// be responsible for. Only requests that contain a macaroon with that specific
8846
// custom caveat are then sent to the middleware for inspection. As a security
8847
// measure, _no_ middleware can intercept requests made with _unencumbered_
8848
// macaroons!
8849
func (r *rpcServer) RegisterRPCMiddleware(
8850
        stream lnrpc.Lightning_RegisterRPCMiddlewareServer) error {
3✔
8851

3✔
8852
        // This is a security critical functionality and needs to be enabled
3✔
8853
        // specifically by the user.
3✔
8854
        if !r.cfg.RPCMiddleware.Enable {
3✔
8855
                return fmt.Errorf("RPC middleware not enabled in config")
×
8856
        }
×
8857

8858
        // When registering a middleware the first message being sent from the
8859
        // middleware must be a registration message containing its name and the
8860
        // custom caveat it wants to register for.
8861
        var (
3✔
8862
                registerChan     = make(chan *lnrpc.MiddlewareRegistration, 1)
3✔
8863
                registerDoneChan = make(chan struct{})
3✔
8864
                errChan          = make(chan error, 1)
3✔
8865
        )
3✔
8866
        ctxc, cancel := context.WithTimeout(
3✔
8867
                stream.Context(), r.cfg.RPCMiddleware.InterceptTimeout,
3✔
8868
        )
3✔
8869
        defer cancel()
3✔
8870

3✔
8871
        // Read the first message in a goroutine because the Recv method blocks
3✔
8872
        // until the message arrives.
3✔
8873
        go func() {
6✔
8874
                msg, err := stream.Recv()
3✔
8875
                if err != nil {
3✔
8876
                        errChan <- err
×
8877

×
8878
                        return
×
8879
                }
×
8880

8881
                registerChan <- msg.GetRegister()
3✔
8882
        }()
8883

8884
        // Wait for the initial message to arrive or time out if it takes too
8885
        // long.
8886
        var registerMsg *lnrpc.MiddlewareRegistration
3✔
8887
        select {
3✔
8888
        case registerMsg = <-registerChan:
3✔
8889
                if registerMsg == nil {
3✔
8890
                        return fmt.Errorf("invalid initial middleware " +
×
8891
                                "registration message")
×
8892
                }
×
8893

8894
        case err := <-errChan:
×
8895
                return fmt.Errorf("error receiving initial middleware "+
×
8896
                        "registration message: %v", err)
×
8897

8898
        case <-ctxc.Done():
×
8899
                return ctxc.Err()
×
8900

8901
        case <-r.quit:
×
8902
                return ErrServerShuttingDown
×
8903
        }
8904

8905
        // Make sure the registration is valid.
8906
        const nameMinLength = 5
3✔
8907
        if len(registerMsg.MiddlewareName) < nameMinLength {
6✔
8908
                return fmt.Errorf("invalid middleware name, use descriptive "+
3✔
8909
                        "name of at least %d characters", nameMinLength)
3✔
8910
        }
3✔
8911

8912
        readOnly := registerMsg.ReadOnlyMode
3✔
8913
        caveatName := registerMsg.CustomMacaroonCaveatName
3✔
8914
        switch {
3✔
8915
        case readOnly && len(caveatName) > 0:
3✔
8916
                return fmt.Errorf("cannot set read-only and custom caveat " +
3✔
8917
                        "name at the same time")
3✔
8918

8919
        case !readOnly && len(caveatName) < nameMinLength:
3✔
8920
                return fmt.Errorf("need to set either custom caveat name "+
3✔
8921
                        "of at least %d characters or read-only mode",
3✔
8922
                        nameMinLength)
3✔
8923
        }
8924

8925
        middleware := rpcperms.NewMiddlewareHandler(
3✔
8926
                registerMsg.MiddlewareName,
3✔
8927
                caveatName, readOnly, stream.Recv, stream.Send,
3✔
8928
                r.cfg.RPCMiddleware.InterceptTimeout,
3✔
8929
                r.cfg.ActiveNetParams.Params, r.quit,
3✔
8930
        )
3✔
8931

3✔
8932
        // Add the RPC middleware to the interceptor chain and defer its
3✔
8933
        // removal.
3✔
8934
        if err := r.interceptorChain.RegisterMiddleware(middleware); err != nil {
3✔
8935
                return fmt.Errorf("error registering middleware: %w", err)
×
8936
        }
×
8937
        defer r.interceptorChain.RemoveMiddleware(registerMsg.MiddlewareName)
3✔
8938

3✔
8939
        // Send a message to the client to indicate that the registration has
3✔
8940
        // successfully completed.
3✔
8941
        regCompleteMsg := &lnrpc.RPCMiddlewareRequest{
3✔
8942
                InterceptType: &lnrpc.RPCMiddlewareRequest_RegComplete{
3✔
8943
                        RegComplete: true,
3✔
8944
                },
3✔
8945
        }
3✔
8946

3✔
8947
        // Send the message in a goroutine because the Send method blocks until
3✔
8948
        // the message is read by the client.
3✔
8949
        go func() {
6✔
8950
                err := stream.Send(regCompleteMsg)
3✔
8951
                if err != nil {
3✔
8952
                        errChan <- err
×
8953
                        return
×
8954
                }
×
8955

8956
                close(registerDoneChan)
3✔
8957
        }()
8958

8959
        select {
3✔
8960
        case err := <-errChan:
×
8961
                return fmt.Errorf("error sending middleware registration "+
×
8962
                        "complete message: %v", err)
×
8963

8964
        case <-ctxc.Done():
×
8965
                return ctxc.Err()
×
8966

8967
        case <-r.quit:
×
8968
                return ErrServerShuttingDown
×
8969

8970
        case <-registerDoneChan:
3✔
8971
        }
8972

8973
        return middleware.Run()
3✔
8974
}
8975

8976
// SendCustomMessage sends a custom peer message.
8977
func (r *rpcServer) SendCustomMessage(_ context.Context,
8978
        req *lnrpc.SendCustomMessageRequest) (*lnrpc.SendCustomMessageResponse,
8979
        error) {
3✔
8980

3✔
8981
        peer, err := route.NewVertexFromBytes(req.Peer)
3✔
8982
        if err != nil {
3✔
8983
                return nil, err
×
8984
        }
×
8985

8986
        err = r.server.SendCustomMessage(
3✔
8987
                peer, lnwire.MessageType(req.Type), req.Data,
3✔
8988
        )
3✔
8989
        switch {
3✔
8990
        case errors.Is(err, ErrPeerNotConnected):
×
8991
                return nil, status.Error(codes.NotFound, err.Error())
×
8992
        case err != nil:
3✔
8993
                return nil, err
3✔
8994
        }
8995

8996
        return &lnrpc.SendCustomMessageResponse{
3✔
8997
                Status: "message sent successfully",
3✔
8998
        }, nil
3✔
8999
}
9000

9001
// SubscribeCustomMessages subscribes to a stream of incoming custom peer
9002
// messages.
9003
func (r *rpcServer) SubscribeCustomMessages(
9004
        _ *lnrpc.SubscribeCustomMessagesRequest,
9005
        server lnrpc.Lightning_SubscribeCustomMessagesServer) error {
3✔
9006

3✔
9007
        client, err := r.server.SubscribeCustomMessages()
3✔
9008
        if err != nil {
3✔
9009
                return err
×
9010
        }
×
9011
        defer client.Cancel()
3✔
9012

3✔
9013
        for {
6✔
9014
                select {
3✔
9015
                case <-client.Quit():
×
9016
                        return errors.New("shutdown")
×
9017

9018
                case <-server.Context().Done():
3✔
9019
                        return server.Context().Err()
3✔
9020

9021
                case update := <-client.Updates():
3✔
9022
                        customMsg := update.(*CustomMessage)
3✔
9023

3✔
9024
                        err := server.Send(&lnrpc.CustomMessage{
3✔
9025
                                Peer: customMsg.Peer[:],
3✔
9026
                                Data: customMsg.Msg.Data,
3✔
9027
                                Type: uint32(customMsg.Msg.Type),
3✔
9028
                        })
3✔
9029
                        if err != nil {
3✔
9030
                                return err
×
9031
                        }
×
9032
                }
9033
        }
9034
}
9035

9036
// ListAliases returns the set of all aliases we have ever allocated along with
9037
// their base SCIDs and possibly a separate confirmed SCID in the case of
9038
// zero-conf.
9039
func (r *rpcServer) ListAliases(_ context.Context,
9040
        _ *lnrpc.ListAliasesRequest) (*lnrpc.ListAliasesResponse, error) {
×
9041

×
9042
        // Fetch the map of all aliases.
×
9043
        mapAliases := r.server.aliasMgr.ListAliases()
×
9044

×
9045
        // Fill out the response. This does not include the zero-conf confirmed
×
9046
        // SCID. Doing so would require more database lookups, and it can be
×
9047
        // cross-referenced with the output of ListChannels/ClosedChannels.
×
9048
        resp := &lnrpc.ListAliasesResponse{
×
9049
                AliasMaps: make([]*lnrpc.AliasMap, 0),
×
9050
        }
×
9051

×
9052
        // Now we need to parse the created mappings into an rpc response.
×
9053
        resp.AliasMaps = lnrpc.MarshalAliasMap(mapAliases)
×
9054

×
9055
        return resp, nil
×
9056
}
×
9057

9058
// rpcInitiator returns the correct lnrpc initiator for channels where we have
9059
// a record of the opening channel.
9060
func rpcInitiator(isInitiator bool) lnrpc.Initiator {
3✔
9061
        if isInitiator {
6✔
9062
                return lnrpc.Initiator_INITIATOR_LOCAL
3✔
9063
        }
3✔
9064

9065
        return lnrpc.Initiator_INITIATOR_REMOTE
3✔
9066
}
9067

9068
// chainSyncInfo wraps info about the best block and whether the system is
9069
// synced to that block.
9070
type chainSyncInfo struct {
9071
        // isSynced specifies whether the whole system is considered synced.
9072
        // When true, it means the following subsystems are at the best height
9073
        // reported by the chain backend,
9074
        // - wallet.
9075
        // - channel graph.
9076
        // - blockbeat dispatcher.
9077
        isSynced bool
9078

9079
        // bestHeight is the current height known to the chain backend.
9080
        bestHeight int32
9081

9082
        // blockHash is the hash of the current block known to the chain
9083
        // backend.
9084
        blockHash chainhash.Hash
9085

9086
        // timestamp is the block's timestamp the wallet has synced to.
9087
        timestamp int64
9088
}
9089

9090
// getChainSyncInfo queries the chain backend, the wallet, the channel router
9091
// and the blockbeat dispatcher to determine the best block and whether the
9092
// system is considered synced.
9093
func (r *rpcServer) getChainSyncInfo() (*chainSyncInfo, error) {
3✔
9094
        bestHash, bestHeight, err := r.server.cc.ChainIO.GetBestBlock()
3✔
9095
        if err != nil {
3✔
9096
                return nil, fmt.Errorf("unable to get best block info: %w", err)
×
9097
        }
×
9098

9099
        isSynced, bestHeaderTimestamp, err := r.server.cc.Wallet.IsSynced()
3✔
9100
        if err != nil {
3✔
9101
                return nil, fmt.Errorf("unable to sync PoV of the wallet "+
×
9102
                        "with current best block in the main chain: %v", err)
×
9103
        }
×
9104

9105
        // Create an info to be returned.
9106
        info := &chainSyncInfo{
3✔
9107
                isSynced:   isSynced,
3✔
9108
                bestHeight: bestHeight,
3✔
9109
                blockHash:  *bestHash,
3✔
9110
                timestamp:  bestHeaderTimestamp,
3✔
9111
        }
3✔
9112

3✔
9113
        // Exit early if the wallet is not synced.
3✔
9114
        if !isSynced {
4✔
9115
                rpcsLog.Debugf("Wallet is not synced to height %v yet",
1✔
9116
                        bestHeight)
1✔
9117

1✔
9118
                return info, nil
1✔
9119
        }
1✔
9120

9121
        // If the router does full channel validation, it has a lot of work to
9122
        // do for each block. So it might be possible that it isn't yet up to
9123
        // date with the most recent block, even if the wallet is. This can
9124
        // happen in environments with high CPU load (such as parallel itests).
9125
        // Since the `synced_to_chain` flag in the response of this call is used
9126
        // by many wallets (and also our itests) to make sure everything's up to
9127
        // date, we add the router's state to it. So the flag will only toggle
9128
        // to true once the router was also able to catch up.
9129
        if !r.cfg.Routing.AssumeChannelValid {
6✔
9130
                routerHeight := r.server.graphBuilder.SyncedHeight()
3✔
9131
                isSynced = uint32(bestHeight) == routerHeight
3✔
9132
        }
3✔
9133

9134
        // Exit early if the channel graph is not synced.
9135
        if !isSynced {
4✔
9136
                rpcsLog.Debugf("Graph is not synced to height %v yet",
1✔
9137
                        bestHeight)
1✔
9138

1✔
9139
                return info, nil
1✔
9140
        }
1✔
9141

9142
        // Given the wallet and the channel router are synced, we now check
9143
        // whether the blockbeat dispatcher is synced.
9144
        height := r.server.blockbeatDispatcher.CurrentHeight()
3✔
9145

3✔
9146
        // Overwrite isSynced and return.
3✔
9147
        info.isSynced = height == bestHeight
3✔
9148

3✔
9149
        if !info.isSynced {
6✔
9150
                rpcsLog.Debugf("Blockbeat is not synced to height %v yet",
3✔
9151
                        bestHeight)
3✔
9152
        }
3✔
9153

9154
        return info, nil
3✔
9155
}
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