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

lightningnetwork / lnd / 14904423814

08 May 2025 10:32AM UTC coverage: 58.577% (-10.4%) from 69.014%
14904423814

Pull #9692

github

web-flow
Merge 8dec9cbed into 43e822c3b
Pull Request #9692: [graph-work-side-branch]: temp side branch for graph work

198 of 341 new or added lines in 31 files covered. (58.06%)

28211 existing lines in 450 files now uncovered.

97442 of 166348 relevant lines covered (58.58%)

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/labels"
60
        "github.com/lightningnetwork/lnd/lncfg"
61
        "github.com/lightningnetwork/lnd/lnrpc"
62
        "github.com/lightningnetwork/lnd/lnrpc/invoicesrpc"
63
        "github.com/lightningnetwork/lnd/lnrpc/routerrpc"
64
        "github.com/lightningnetwork/lnd/lnrpc/walletrpc"
65
        "github.com/lightningnetwork/lnd/lntypes"
66
        "github.com/lightningnetwork/lnd/lnutils"
67
        "github.com/lightningnetwork/lnd/lnwallet"
68
        "github.com/lightningnetwork/lnd/lnwallet/btcwallet"
69
        "github.com/lightningnetwork/lnd/lnwallet/chainfee"
70
        "github.com/lightningnetwork/lnd/lnwallet/chancloser"
71
        "github.com/lightningnetwork/lnd/lnwallet/chanfunding"
72
        "github.com/lightningnetwork/lnd/lnwire"
73
        "github.com/lightningnetwork/lnd/macaroons"
74
        "github.com/lightningnetwork/lnd/peer"
75
        "github.com/lightningnetwork/lnd/peernotifier"
76
        "github.com/lightningnetwork/lnd/record"
77
        "github.com/lightningnetwork/lnd/routing"
78
        "github.com/lightningnetwork/lnd/routing/blindedpath"
79
        "github.com/lightningnetwork/lnd/routing/route"
80
        "github.com/lightningnetwork/lnd/rpcperms"
81
        "github.com/lightningnetwork/lnd/signal"
82
        "github.com/lightningnetwork/lnd/sweep"
83
        "github.com/lightningnetwork/lnd/tlv"
84
        "github.com/lightningnetwork/lnd/watchtower"
85
        "github.com/lightningnetwork/lnd/zpay32"
86
        "github.com/tv42/zbase32"
87
        "google.golang.org/grpc"
88
        "google.golang.org/grpc/codes"
89
        "google.golang.org/grpc/status"
90
        "google.golang.org/protobuf/proto"
91
        "gopkg.in/macaroon-bakery.v2/bakery"
92
)
93

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

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

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

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

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

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

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

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

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

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

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

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

UNCOV
274
        return allPerms
×
275
}
276

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

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

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

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

605
        server *server
606

607
        cfg *Config
608

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

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

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

625
        quit chan struct{}
626

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

3✔
881
                        r.describeGraphResp = nil
3✔
882

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

889
        return nil
3✔
890
}
891

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

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

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

921
        return nil
3✔
922
}
923

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

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

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

943
        return nil
3✔
944
}
945

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

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

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

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

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

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

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

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

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

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

1017
        return nil
3✔
1018
}
1019

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

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

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

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

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

1047
        return outputs, nil
3✔
1048
}
1049

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

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

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

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

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

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

3✔
1086
                                break
3✔
1087
                        }
1088
                }
1089

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

3✔
1300
        return defaultNumBlocksEstimate
3✔
1301
}
1302

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

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

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

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

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

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

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

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

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

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

1373
        var txid *chainhash.Hash
3✔
1374

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

×
1497
                        return nil, err
×
1498
                }
×
1499

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

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

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

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

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

1532
                        txid = newTXID
3✔
1533

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

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

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

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

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

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

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

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

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

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

×
1589
        var txid *chainhash.Hash
×
1590

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

1604
                txid = sendManyTXID
×
1605

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2043
        return nil
3✔
2044
}
2045

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2182
        var nodePubKey *btcec.PublicKey
3✔
2183

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2416
        return wireOutpoints, nil
3✔
2417
}
2418

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2869
                var deliveryScript lnwire.DeliveryAddress
3✔
2870

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

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

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

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

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

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

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

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

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

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

3✔
2961
                        return err
3✔
2962

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

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

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

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

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

3✔
3000
                                break out
3✔
3001
                        }
3002

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

3008
        return nil
3✔
3009
}
3010

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

3✔
3180
        return nil
3✔
3181
}
3182

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

3642
                        fallthrough
3✔
3643

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

3649
                default:
3✔
3650
                }
3651

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

3853
        return resp, nil
3✔
3854
}
3855

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

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

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

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

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

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

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

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

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

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

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

3950
        return result, nil
3✔
3951
}
3952

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

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

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

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

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

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

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

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

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

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

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

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

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

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

3✔
4047
                switch pendingClose.CloseType {
3✔
4048

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

3✔
4162
                var commitments lnrpc.PendingChannelsResponse_Commitments
3✔
4163

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

4345
        return resp, nil
3✔
4346
}
4347

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

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

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

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

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

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

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

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

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

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

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

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

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

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

4428
        return nil
3✔
4429
}
4430

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

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

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

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

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

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

4478
        return nil
×
4479
}
4480

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

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

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

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

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

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

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

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

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

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

4556
        return resp, nil
3✔
4557
}
4558

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

4679
        return resp, nil
3✔
4680
}
4681

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

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

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

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

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

4704
        default:
3✔
4705

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

5023
        return channel, nil
3✔
5024
}
5025

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

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

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

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

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

5065
        dbScid := dbChannel.ShortChanID
3✔
5066

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

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

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

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

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

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

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

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

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

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

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

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

5152
        return channel, nil
3✔
5153
}
5154

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

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

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

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

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

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

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

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

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

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

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

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

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

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

5206
        return res, nil
3✔
5207
}
5208

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

3✔
5369
                                continue
3✔
5370

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

5519
        destCustomRecords record.CustomSet
5520

5521
        route *route.Route
5522
}
5523

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

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

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

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

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

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

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

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

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

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

5596
                return nil
×
5597
        }
5598

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

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

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

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

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

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

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

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

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

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

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

5688
                return payIntent, nil
×
5689
        }
5690

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

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

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

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

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

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

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

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

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

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

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

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

5787
        return payIntent, nil
×
5788
}
5789

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

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

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

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

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

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

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

5855
                route = payIntent.route
3✔
5856
        }
5857

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

3✔
6244
                                // The invoice payer will also need to
3✔
6245
                                // understand the new BOLT 11 tagged field
3✔
6246
                                // containing the blinded path, so we switch
3✔
6247
                                // the bit to required.
3✔
6248
                                v = feature.SetBit(
3✔
6249
                                        v, lnwire.Bolt11BlindedPathsRequired,
3✔
6250
                                )
3✔
6251
                        }
3✔
6252

6253
                        return v
3✔
6254
                },
6255
                GenAmpInvoiceFeatures: func() *lnwire.FeatureVector {
3✔
6256
                        return r.server.featureMgr.Get(feature.SetInvoiceAmp)
3✔
6257
                },
3✔
6258
                GetAlias:   r.server.aliasMgr.GetPeerAlias,
6259
                BestHeight: r.server.cc.BestBlockTracker.BestHeight,
6260
                QueryBlindedRoutes: func(amt lnwire.MilliSatoshi) (
6261
                        []*route.Route, error) {
3✔
6262

3✔
6263
                        return r.server.chanRouter.FindBlindedPaths(
3✔
6264
                                r.selfNode, amt,
3✔
6265
                                r.server.defaultMC.GetProbability,
3✔
6266
                                blindingRestrictions,
3✔
6267
                        )
3✔
6268
                },
3✔
6269
        }
6270

6271
        value, err := lnrpc.UnmarshallAmt(invoice.Value, invoice.ValueMsat)
3✔
6272
        if err != nil {
3✔
6273
                return nil, err
×
6274
        }
×
6275

6276
        // Convert the passed routing hints to the required format.
6277
        routeHints, err := invoicesrpc.CreateZpay32HopHints(invoice.RouteHints)
3✔
6278
        if err != nil {
3✔
6279
                return nil, err
×
6280
        }
×
6281

6282
        var blindedPathCfg *invoicesrpc.BlindedPathConfig
3✔
6283
        if blind {
6✔
6284
                bpConfig := r.server.cfg.Routing.BlindedPaths
3✔
6285

3✔
6286
                blindedPathCfg = &invoicesrpc.BlindedPathConfig{
3✔
6287
                        RoutePolicyIncrMultiplier: bpConfig.
3✔
6288
                                PolicyIncreaseMultiplier,
3✔
6289
                        RoutePolicyDecrMultiplier: bpConfig.
3✔
6290
                                PolicyDecreaseMultiplier,
3✔
6291
                        DefaultDummyHopPolicy: &blindedpath.BlindedHopPolicy{
3✔
6292
                                CLTVExpiryDelta: uint16(defaultDelta),
3✔
6293
                                FeeRate: uint32(
3✔
6294
                                        r.server.cfg.Bitcoin.FeeRate,
3✔
6295
                                ),
3✔
6296
                                BaseFee:     r.server.cfg.Bitcoin.BaseFee,
3✔
6297
                                MinHTLCMsat: r.server.cfg.Bitcoin.MinHTLCIn,
3✔
6298

3✔
6299
                                // MaxHTLCMsat will be calculated on the fly by
3✔
6300
                                // using the introduction node's channel's
3✔
6301
                                // capacities.
3✔
6302
                                MaxHTLCMsat: 0,
3✔
6303
                        },
3✔
6304
                        MinNumPathHops: blindingRestrictions.NumHops,
3✔
6305
                }
3✔
6306
        }
3✔
6307

6308
        addInvoiceData := &invoicesrpc.AddInvoiceData{
3✔
6309
                Memo:            invoice.Memo,
3✔
6310
                Value:           value,
3✔
6311
                DescriptionHash: invoice.DescriptionHash,
3✔
6312
                Expiry:          invoice.Expiry,
3✔
6313
                FallbackAddr:    invoice.FallbackAddr,
3✔
6314
                CltvExpiry:      invoice.CltvExpiry,
3✔
6315
                Private:         invoice.Private,
3✔
6316
                RouteHints:      routeHints,
3✔
6317
                Amp:             invoice.IsAmp,
3✔
6318
                BlindedPathCfg:  blindedPathCfg,
3✔
6319
        }
3✔
6320

3✔
6321
        if invoice.RPreimage != nil {
6✔
6322
                preimage, err := lntypes.MakePreimage(invoice.RPreimage)
3✔
6323
                if err != nil {
3✔
6324
                        return nil, err
×
6325
                }
×
6326
                addInvoiceData.Preimage = &preimage
3✔
6327
        }
6328

6329
        hash, dbInvoice, err := invoicesrpc.AddInvoice(
3✔
6330
                ctx, addInvoiceCfg, addInvoiceData,
3✔
6331
        )
3✔
6332
        if err != nil {
3✔
6333
                return nil, err
×
6334
        }
×
6335

6336
        return &lnrpc.AddInvoiceResponse{
3✔
6337
                AddIndex:       dbInvoice.AddIndex,
3✔
6338
                PaymentRequest: string(dbInvoice.PaymentRequest),
3✔
6339
                RHash:          hash[:],
3✔
6340
                PaymentAddr:    dbInvoice.Terms.PaymentAddr[:],
3✔
6341
        }, nil
3✔
6342
}
6343

6344
// LookupInvoice attempts to look up an invoice according to its payment hash.
6345
// The passed payment hash *must* be exactly 32 bytes, if not an error is
6346
// returned.
6347
func (r *rpcServer) LookupInvoice(ctx context.Context,
6348
        req *lnrpc.PaymentHash) (*lnrpc.Invoice, error) {
3✔
6349

3✔
6350
        var (
3✔
6351
                payHash [32]byte
3✔
6352
                rHash   []byte
3✔
6353
                err     error
3✔
6354
        )
3✔
6355

3✔
6356
        // If the RHash as a raw string was provided, then decode that and use
3✔
6357
        // that directly. Otherwise, we use the raw bytes provided.
3✔
6358
        if req.RHashStr != "" {
6✔
6359
                rHash, err = hex.DecodeString(req.RHashStr)
3✔
6360
                if err != nil {
3✔
6361
                        return nil, err
×
6362
                }
×
6363
        } else {
3✔
6364
                rHash = req.RHash
3✔
6365
        }
3✔
6366

6367
        // Ensure that the payment hash is *exactly* 32-bytes.
6368
        if len(rHash) != 0 && len(rHash) != 32 {
3✔
6369
                return nil, fmt.Errorf("payment hash must be exactly "+
×
6370
                        "32 bytes, is instead %v", len(rHash))
×
6371
        }
×
6372
        copy(payHash[:], rHash)
3✔
6373

3✔
6374
        rpcsLog.Tracef("[lookupinvoice] searching for invoice %x", payHash[:])
3✔
6375

3✔
6376
        invoice, err := r.server.invoices.LookupInvoice(ctx, payHash)
3✔
6377
        switch {
3✔
6378
        case errors.Is(err, invoices.ErrInvoiceNotFound):
×
6379
                return nil, status.Error(codes.NotFound, err.Error())
×
6380
        case err != nil:
×
6381
                return nil, err
×
6382
        }
6383

6384
        rpcsLog.Tracef("[lookupinvoice] located invoice %v",
3✔
6385
                lnutils.SpewLogClosure(invoice))
3✔
6386

3✔
6387
        rpcInvoice, err := invoicesrpc.CreateRPCInvoice(
3✔
6388
                &invoice, r.cfg.ActiveNetParams.Params,
3✔
6389
        )
3✔
6390
        if err != nil {
3✔
6391
                return nil, err
×
6392
        }
×
6393

6394
        // Give the aux data parser a chance to format the custom data in the
6395
        // invoice HTLCs.
6396
        err = fn.MapOptionZ(
3✔
6397
                r.server.implCfg.AuxDataParser,
3✔
6398
                func(parser AuxDataParser) error {
3✔
6399
                        return parser.InlineParseCustomData(rpcInvoice)
×
6400
                },
×
6401
        )
6402
        if err != nil {
3✔
6403
                return nil, fmt.Errorf("error parsing custom data: %w",
×
6404
                        err)
×
6405
        }
×
6406

6407
        return rpcInvoice, nil
3✔
6408
}
6409

6410
// ListInvoices returns a list of all the invoices currently stored within the
6411
// database. Any active debug invoices are ignored.
6412
func (r *rpcServer) ListInvoices(ctx context.Context,
6413
        req *lnrpc.ListInvoiceRequest) (*lnrpc.ListInvoiceResponse, error) {
3✔
6414

3✔
6415
        // If the number of invoices was not specified, then we'll default to
3✔
6416
        // returning the latest 100 invoices.
3✔
6417
        if req.NumMaxInvoices == 0 {
6✔
6418
                req.NumMaxInvoices = 100
3✔
6419
        }
3✔
6420

6421
        // If both dates are set, we check that the start date is less than the
6422
        // end date, otherwise we'll get an empty result.
6423
        if req.CreationDateStart != 0 && req.CreationDateEnd != 0 {
3✔
6424
                if req.CreationDateStart >= req.CreationDateEnd {
×
6425
                        return nil, fmt.Errorf("start date(%v) must be before "+
×
6426
                                "end date(%v)", req.CreationDateStart,
×
6427
                                req.CreationDateEnd)
×
6428
                }
×
6429
        }
6430

6431
        // Next, we'll map the proto request into a format that is understood by
6432
        // the database.
6433
        q := invoices.InvoiceQuery{
3✔
6434
                IndexOffset:       req.IndexOffset,
3✔
6435
                NumMaxInvoices:    req.NumMaxInvoices,
3✔
6436
                PendingOnly:       req.PendingOnly,
3✔
6437
                Reversed:          req.Reversed,
3✔
6438
                CreationDateStart: int64(req.CreationDateStart),
3✔
6439
                CreationDateEnd:   int64(req.CreationDateEnd),
3✔
6440
        }
3✔
6441

3✔
6442
        invoiceSlice, err := r.server.invoicesDB.QueryInvoices(ctx, q)
3✔
6443
        if err != nil {
3✔
6444
                return nil, fmt.Errorf("unable to query invoices: %w", err)
×
6445
        }
×
6446

6447
        // Before returning the response, we'll need to convert each invoice
6448
        // into it's proto representation.
6449
        resp := &lnrpc.ListInvoiceResponse{
3✔
6450
                Invoices:         make([]*lnrpc.Invoice, len(invoiceSlice.Invoices)),
3✔
6451
                FirstIndexOffset: invoiceSlice.FirstIndexOffset,
3✔
6452
                LastIndexOffset:  invoiceSlice.LastIndexOffset,
3✔
6453
        }
3✔
6454
        for i, invoice := range invoiceSlice.Invoices {
6✔
6455
                invoice := invoice
3✔
6456
                resp.Invoices[i], err = invoicesrpc.CreateRPCInvoice(
3✔
6457
                        &invoice, r.cfg.ActiveNetParams.Params,
3✔
6458
                )
3✔
6459
                if err != nil {
3✔
6460
                        return nil, err
×
6461
                }
×
6462

6463
                // Give the aux data parser a chance to format the custom data
6464
                // in the invoice HTLCs.
6465
                err = fn.MapOptionZ(
3✔
6466
                        r.server.implCfg.AuxDataParser,
3✔
6467
                        func(parser AuxDataParser) error {
3✔
6468
                                return parser.InlineParseCustomData(
×
6469
                                        resp.Invoices[i],
×
6470
                                )
×
6471
                        },
×
6472
                )
6473
                if err != nil {
3✔
6474
                        return nil, fmt.Errorf("error parsing custom data: %w",
×
6475
                                err)
×
6476
                }
×
6477
        }
6478

6479
        return resp, nil
3✔
6480
}
6481

6482
// SubscribeInvoices returns a uni-directional stream (server -> client) for
6483
// notifying the client of newly added/settled invoices.
6484
func (r *rpcServer) SubscribeInvoices(req *lnrpc.InvoiceSubscription,
6485
        updateStream lnrpc.Lightning_SubscribeInvoicesServer) error {
3✔
6486

3✔
6487
        invoiceClient, err := r.server.invoices.SubscribeNotifications(
3✔
6488
                updateStream.Context(), req.AddIndex, req.SettleIndex,
3✔
6489
        )
3✔
6490
        if err != nil {
3✔
6491
                return err
×
6492
        }
×
6493
        defer invoiceClient.Cancel()
3✔
6494

3✔
6495
        for {
6✔
6496
                select {
3✔
6497
                case newInvoice := <-invoiceClient.NewInvoices:
3✔
6498
                        rpcInvoice, err := invoicesrpc.CreateRPCInvoice(
3✔
6499
                                newInvoice, r.cfg.ActiveNetParams.Params,
3✔
6500
                        )
3✔
6501
                        if err != nil {
3✔
6502
                                return err
×
6503
                        }
×
6504

6505
                        // Give the aux data parser a chance to format the
6506
                        // custom data in the invoice HTLCs.
6507
                        err = fn.MapOptionZ(
3✔
6508
                                r.server.implCfg.AuxDataParser,
3✔
6509
                                func(parser AuxDataParser) error {
3✔
6510
                                        return parser.InlineParseCustomData(
×
6511
                                                rpcInvoice,
×
6512
                                        )
×
6513
                                },
×
6514
                        )
6515
                        if err != nil {
3✔
6516
                                return fmt.Errorf("error parsing custom data: "+
×
6517
                                        "%w", err)
×
6518
                        }
×
6519

6520
                        if err := updateStream.Send(rpcInvoice); err != nil {
3✔
6521
                                return err
×
6522
                        }
×
6523

6524
                case settledInvoice := <-invoiceClient.SettledInvoices:
3✔
6525
                        rpcInvoice, err := invoicesrpc.CreateRPCInvoice(
3✔
6526
                                settledInvoice, r.cfg.ActiveNetParams.Params,
3✔
6527
                        )
3✔
6528
                        if err != nil {
3✔
6529
                                return err
×
6530
                        }
×
6531

6532
                        // Give the aux data parser a chance to format the
6533
                        // custom data in the invoice HTLCs.
6534
                        err = fn.MapOptionZ(
3✔
6535
                                r.server.implCfg.AuxDataParser,
3✔
6536
                                func(parser AuxDataParser) error {
3✔
6537
                                        return parser.InlineParseCustomData(
×
6538
                                                rpcInvoice,
×
6539
                                        )
×
6540
                                },
×
6541
                        )
6542
                        if err != nil {
3✔
6543
                                return fmt.Errorf("error parsing custom data: "+
×
6544
                                        "%w", err)
×
6545
                        }
×
6546

6547
                        if err := updateStream.Send(rpcInvoice); err != nil {
3✔
6548
                                return err
×
6549
                        }
×
6550

6551
                // The response stream's context for whatever reason has been
6552
                // closed. If context is closed by an exceeded deadline we will
6553
                // return an error.
6554
                case <-updateStream.Context().Done():
3✔
6555
                        if errors.Is(updateStream.Context().Err(), context.Canceled) {
6✔
6556
                                return nil
3✔
6557
                        }
3✔
6558
                        return updateStream.Context().Err()
×
6559

6560
                case <-r.quit:
×
6561
                        return nil
×
6562
                }
6563
        }
6564
}
6565

6566
// SubscribeTransactions creates a uni-directional stream (server -> client) in
6567
// which any newly discovered transactions relevant to the wallet are sent
6568
// over.
6569
func (r *rpcServer) SubscribeTransactions(req *lnrpc.GetTransactionsRequest,
6570
        updateStream lnrpc.Lightning_SubscribeTransactionsServer) error {
×
6571

×
6572
        txClient, err := r.server.cc.Wallet.SubscribeTransactions()
×
6573
        if err != nil {
×
6574
                return err
×
6575
        }
×
6576
        defer txClient.Cancel()
×
6577
        rpcsLog.Infof("New transaction subscription")
×
6578

×
6579
        for {
×
6580
                select {
×
6581
                case tx := <-txClient.ConfirmedTransactions():
×
6582
                        detail := lnrpc.RPCTransaction(tx)
×
6583
                        if err := updateStream.Send(detail); err != nil {
×
6584
                                return err
×
6585
                        }
×
6586

6587
                case tx := <-txClient.UnconfirmedTransactions():
×
6588
                        detail := lnrpc.RPCTransaction(tx)
×
6589
                        if err := updateStream.Send(detail); err != nil {
×
6590
                                return err
×
6591
                        }
×
6592

6593
                // The response stream's context for whatever reason has been
6594
                // closed. If context is closed by an exceeded deadline we will
6595
                // return an error.
6596
                case <-updateStream.Context().Done():
×
6597
                        rpcsLog.Infof("Canceling transaction subscription")
×
6598
                        if errors.Is(updateStream.Context().Err(), context.Canceled) {
×
6599
                                return nil
×
6600
                        }
×
6601
                        return updateStream.Context().Err()
×
6602

6603
                case <-r.quit:
×
6604
                        return nil
×
6605
                }
6606
        }
6607
}
6608

6609
// GetTransactions returns a list of describing all the known transactions
6610
// relevant to the wallet.
6611
func (r *rpcServer) GetTransactions(ctx context.Context,
6612
        req *lnrpc.GetTransactionsRequest) (*lnrpc.TransactionDetails, error) {
3✔
6613

3✔
6614
        // To remain backwards compatible with the old api, default to the
3✔
6615
        // special case end height which will return transactions from the start
3✔
6616
        // height until the chain tip, including unconfirmed transactions.
3✔
6617
        var endHeight = btcwallet.UnconfirmedHeight
3✔
6618

3✔
6619
        // If the user has provided an end height, we overwrite our default.
3✔
6620
        if req.EndHeight != 0 {
6✔
6621
                endHeight = req.EndHeight
3✔
6622
        }
3✔
6623

6624
        txns, firstIdx, lastIdx, err :=
3✔
6625
                r.server.cc.Wallet.ListTransactionDetails(
3✔
6626
                        req.StartHeight, endHeight, req.Account,
3✔
6627
                        req.IndexOffset, req.MaxTransactions,
3✔
6628
                )
3✔
6629
        if err != nil {
3✔
6630
                return nil, err
×
6631
        }
×
6632

6633
        return lnrpc.RPCTransactionDetails(txns, firstIdx, lastIdx), nil
3✔
6634
}
6635

6636
// DescribeGraph returns a description of the latest graph state from the PoV
6637
// of the node. The graph information is partitioned into two components: all
6638
// the nodes/vertexes, and all the edges that connect the vertexes themselves.
6639
// As this is a directed graph, the edges also contain the node directional
6640
// specific routing policy which includes: the time lock delta, fee
6641
// information, etc.
6642
func (r *rpcServer) DescribeGraph(ctx context.Context,
6643
        req *lnrpc.ChannelGraphRequest) (*lnrpc.ChannelGraph, error) {
3✔
6644

3✔
6645
        resp := &lnrpc.ChannelGraph{}
3✔
6646
        includeUnannounced := req.IncludeUnannounced
3✔
6647

3✔
6648
        // Check to see if the cache is already populated, if so then we can
3✔
6649
        // just return it directly.
3✔
6650
        //
3✔
6651
        // TODO(roasbeef): move this to an interceptor level feature?
3✔
6652
        graphCacheActive := r.cfg.Caches.RPCGraphCacheDuration != 0
3✔
6653
        if graphCacheActive {
6✔
6654
                r.graphCache.Lock()
3✔
6655
                defer r.graphCache.Unlock()
3✔
6656

3✔
6657
                if r.describeGraphResp != nil {
6✔
6658
                        return r.describeGraphResp, nil
3✔
6659
                }
3✔
6660
        }
6661

6662
        // Obtain the pointer to the global singleton channel graph, this will
6663
        // provide a consistent view of the graph due to bolt db's
6664
        // transactional model.
6665
        graph := r.server.graphDB
3✔
6666

3✔
6667
        // First iterate through all the known nodes (connected or unconnected
3✔
6668
        // within the graph), collating their current state into the RPC
3✔
6669
        // response.
3✔
6670
        err := graph.ForEachNode(func(nodeTx graphdb.NodeRTx) error {
6✔
6671
                lnNode := marshalNode(nodeTx.Node())
3✔
6672

3✔
6673
                resp.Nodes = append(resp.Nodes, lnNode)
3✔
6674

3✔
6675
                return nil
3✔
6676
        })
3✔
6677
        if err != nil {
3✔
6678
                return nil, err
×
6679
        }
×
6680

6681
        // Next, for each active channel we know of within the graph, create a
6682
        // similar response which details both the edge information as well as
6683
        // the routing policies of th nodes connecting the two edges.
6684
        err = graph.ForEachChannel(func(edgeInfo *models.ChannelEdgeInfo,
3✔
6685
                c1, c2 *models.ChannelEdgePolicy) error {
6✔
6686

3✔
6687
                // Do not include unannounced channels unless specifically
3✔
6688
                // requested. Unannounced channels include both private channels as
3✔
6689
                // well as public channels whose authentication proof were not
3✔
6690
                // confirmed yet, hence were not announced.
3✔
6691
                if !includeUnannounced && edgeInfo.AuthProof == nil {
6✔
6692
                        return nil
3✔
6693
                }
3✔
6694

6695
                edge := marshalDBEdge(edgeInfo, c1, c2)
3✔
6696
                resp.Edges = append(resp.Edges, edge)
3✔
6697

3✔
6698
                return nil
3✔
6699
        })
6700
        if err != nil && !errors.Is(err, graphdb.ErrGraphNoEdgesFound) {
3✔
6701
                return nil, err
×
6702
        }
×
6703

6704
        // We still have the mutex held, so we can safely populate the cache
6705
        // now to save on GC churn for this query, but only if the cache isn't
6706
        // disabled.
6707
        if graphCacheActive {
6✔
6708
                r.describeGraphResp = resp
3✔
6709
        }
3✔
6710

6711
        return resp, nil
3✔
6712
}
6713

6714
// marshalExtraOpaqueData marshals the given tlv data. If the tlv stream is
6715
// malformed or empty, an empty map is returned. This makes the method safe to
6716
// use on unvalidated data.
6717
func marshalExtraOpaqueData(data []byte) map[uint64][]byte {
3✔
6718
        r := bytes.NewReader(data)
3✔
6719

3✔
6720
        tlvStream, err := tlv.NewStream()
3✔
6721
        if err != nil {
3✔
6722
                return nil
×
6723
        }
×
6724

6725
        // Since ExtraOpaqueData is provided by a potentially malicious peer,
6726
        // pass it into the P2P decoding variant.
6727
        parsedTypes, err := tlvStream.DecodeWithParsedTypesP2P(r)
3✔
6728
        if err != nil || len(parsedTypes) == 0 {
6✔
6729
                return nil
3✔
6730
        }
3✔
6731

6732
        records := make(map[uint64][]byte)
3✔
6733
        for k, v := range parsedTypes {
6✔
6734
                records[uint64(k)] = v
3✔
6735
        }
3✔
6736

6737
        return records
3✔
6738
}
6739

6740
// extractInboundFeeSafe tries to extract the inbound fee from the given extra
6741
// opaque data tlv block. If parsing fails, a zero inbound fee is returned. This
6742
// function is typically used on unvalidated data coming stored in the database.
6743
// There is not much we can do other than ignoring errors here.
6744
func extractInboundFeeSafe(data lnwire.ExtraOpaqueData) lnwire.Fee {
3✔
6745
        var inboundFee lnwire.Fee
3✔
6746

3✔
6747
        _, err := data.ExtractRecords(&inboundFee)
3✔
6748
        if err != nil {
3✔
6749
                // Return zero fee. Do not return the inboundFee variable
×
6750
                // because it may be undefined.
×
6751
                return lnwire.Fee{}
×
6752
        }
×
6753

6754
        return inboundFee
3✔
6755
}
6756

6757
func marshalDBEdge(edgeInfo *models.ChannelEdgeInfo,
6758
        c1, c2 *models.ChannelEdgePolicy) *lnrpc.ChannelEdge {
3✔
6759

3✔
6760
        // Make sure the policies match the node they belong to. c1 should point
3✔
6761
        // to the policy for NodeKey1, and c2 for NodeKey2.
3✔
6762
        if c1 != nil && c1.ChannelFlags&lnwire.ChanUpdateDirection == 1 ||
3✔
6763
                c2 != nil && c2.ChannelFlags&lnwire.ChanUpdateDirection == 0 {
3✔
6764

×
6765
                c2, c1 = c1, c2
×
6766
        }
×
6767

6768
        var lastUpdate int64
3✔
6769
        if c1 != nil {
6✔
6770
                lastUpdate = c1.LastUpdate.Unix()
3✔
6771
        }
3✔
6772
        if c2 != nil && c2.LastUpdate.Unix() > lastUpdate {
6✔
6773
                lastUpdate = c2.LastUpdate.Unix()
3✔
6774
        }
3✔
6775

6776
        customRecords := marshalExtraOpaqueData(edgeInfo.ExtraOpaqueData)
3✔
6777

3✔
6778
        edge := &lnrpc.ChannelEdge{
3✔
6779
                ChannelId: edgeInfo.ChannelID,
3✔
6780
                ChanPoint: edgeInfo.ChannelPoint.String(),
3✔
6781
                // TODO(roasbeef): update should be on edge info itself
3✔
6782
                LastUpdate:    uint32(lastUpdate),
3✔
6783
                Node1Pub:      hex.EncodeToString(edgeInfo.NodeKey1Bytes[:]),
3✔
6784
                Node2Pub:      hex.EncodeToString(edgeInfo.NodeKey2Bytes[:]),
3✔
6785
                Capacity:      int64(edgeInfo.Capacity),
3✔
6786
                CustomRecords: customRecords,
3✔
6787
        }
3✔
6788

3✔
6789
        if c1 != nil {
6✔
6790
                edge.Node1Policy = marshalDBRoutingPolicy(c1)
3✔
6791
        }
3✔
6792

6793
        if c2 != nil {
6✔
6794
                edge.Node2Policy = marshalDBRoutingPolicy(c2)
3✔
6795
        }
3✔
6796

6797
        return edge
3✔
6798
}
6799

6800
func marshalDBRoutingPolicy(
6801
        policy *models.ChannelEdgePolicy) *lnrpc.RoutingPolicy {
3✔
6802

3✔
6803
        disabled := policy.ChannelFlags&lnwire.ChanUpdateDisabled != 0
3✔
6804

3✔
6805
        customRecords := marshalExtraOpaqueData(policy.ExtraOpaqueData)
3✔
6806
        inboundFee := extractInboundFeeSafe(policy.ExtraOpaqueData)
3✔
6807

3✔
6808
        return &lnrpc.RoutingPolicy{
3✔
6809
                TimeLockDelta:    uint32(policy.TimeLockDelta),
3✔
6810
                MinHtlc:          int64(policy.MinHTLC),
3✔
6811
                MaxHtlcMsat:      uint64(policy.MaxHTLC),
3✔
6812
                FeeBaseMsat:      int64(policy.FeeBaseMSat),
3✔
6813
                FeeRateMilliMsat: int64(policy.FeeProportionalMillionths),
3✔
6814
                Disabled:         disabled,
3✔
6815
                LastUpdate:       uint32(policy.LastUpdate.Unix()),
3✔
6816
                CustomRecords:    customRecords,
3✔
6817

3✔
6818
                InboundFeeBaseMsat:      inboundFee.BaseFee,
3✔
6819
                InboundFeeRateMilliMsat: inboundFee.FeeRate,
3✔
6820
        }
3✔
6821
}
3✔
6822

6823
// GetNodeMetrics returns all available node metrics calculated from the
6824
// current channel graph.
6825
func (r *rpcServer) GetNodeMetrics(ctx context.Context,
6826
        req *lnrpc.NodeMetricsRequest) (*lnrpc.NodeMetricsResponse, error) {
×
6827

×
6828
        // Get requested metric types.
×
6829
        getCentrality := false
×
6830
        for _, t := range req.Types {
×
6831
                if t == lnrpc.NodeMetricType_BETWEENNESS_CENTRALITY {
×
6832
                        getCentrality = true
×
6833
                }
×
6834
        }
6835

6836
        // Only centrality can be requested for now.
6837
        if !getCentrality {
×
6838
                return nil, nil
×
6839
        }
×
6840

6841
        resp := &lnrpc.NodeMetricsResponse{
×
6842
                BetweennessCentrality: make(map[string]*lnrpc.FloatMetric),
×
6843
        }
×
6844

×
6845
        // Obtain the pointer to the global singleton channel graph, this will
×
6846
        // provide a consistent view of the graph due to bolt db's
×
6847
        // transactional model.
×
6848
        graph := r.server.graphDB
×
6849

×
6850
        // Calculate betweenness centrality if requested. Note that depending on the
×
6851
        // graph size, this may take up to a few minutes.
×
6852
        channelGraph := autopilot.ChannelGraphFromDatabase(graph)
×
6853
        centralityMetric, err := autopilot.NewBetweennessCentralityMetric(
×
6854
                runtime.NumCPU(),
×
6855
        )
×
6856
        if err != nil {
×
6857
                return nil, err
×
6858
        }
×
NEW
6859
        if err := centralityMetric.Refresh(ctx, channelGraph); err != nil {
×
6860
                return nil, err
×
6861
        }
×
6862

6863
        // Fill normalized and non normalized centrality.
6864
        centrality := centralityMetric.GetMetric(true)
×
6865
        for nodeID, val := range centrality {
×
6866
                resp.BetweennessCentrality[hex.EncodeToString(nodeID[:])] =
×
6867
                        &lnrpc.FloatMetric{
×
6868
                                NormalizedValue: val,
×
6869
                        }
×
6870
        }
×
6871

6872
        centrality = centralityMetric.GetMetric(false)
×
6873
        for nodeID, val := range centrality {
×
6874
                resp.BetweennessCentrality[hex.EncodeToString(nodeID[:])].Value = val
×
6875
        }
×
6876

6877
        return resp, nil
×
6878
}
6879

6880
// GetChanInfo returns the latest authenticated network announcement for the
6881
// given channel identified by either its channel ID or a channel outpoint. Both
6882
// uniquely identify the location of transaction's funding output within the
6883
// blockchain. The former is an 8-byte integer, while the latter is a string
6884
// formatted as funding_txid:output_index.
6885
func (r *rpcServer) GetChanInfo(_ context.Context,
6886
        in *lnrpc.ChanInfoRequest) (*lnrpc.ChannelEdge, error) {
3✔
6887

3✔
6888
        graph := r.server.graphDB
3✔
6889

3✔
6890
        var (
3✔
6891
                edgeInfo     *models.ChannelEdgeInfo
3✔
6892
                edge1, edge2 *models.ChannelEdgePolicy
3✔
6893
                err          error
3✔
6894
        )
3✔
6895

3✔
6896
        switch {
3✔
6897
        case in.ChanId != 0:
3✔
6898
                edgeInfo, edge1, edge2, err = graph.FetchChannelEdgesByID(
3✔
6899
                        in.ChanId,
3✔
6900
                )
3✔
6901

6902
        case in.ChanPoint != "":
3✔
6903
                var chanPoint *wire.OutPoint
3✔
6904
                chanPoint, err = wire.NewOutPointFromString(in.ChanPoint)
3✔
6905
                if err != nil {
3✔
6906
                        return nil, err
×
6907
                }
×
6908
                edgeInfo, edge1, edge2, err = graph.FetchChannelEdgesByOutpoint(
3✔
6909
                        chanPoint,
3✔
6910
                )
3✔
6911

6912
        default:
×
6913
                return nil, fmt.Errorf("specify either chan_id or chan_point")
×
6914
        }
6915
        if err != nil {
6✔
6916
                return nil, err
3✔
6917
        }
3✔
6918

6919
        // Convert the database's edge format into the network/RPC edge format
6920
        // which couples the edge itself along with the directional node
6921
        // routing policies of each node involved within the channel.
6922
        channelEdge := marshalDBEdge(edgeInfo, edge1, edge2)
3✔
6923

3✔
6924
        return channelEdge, nil
3✔
6925
}
6926

6927
// GetNodeInfo returns the latest advertised and aggregate authenticated
6928
// channel information for the specified node identified by its public key.
6929
func (r *rpcServer) GetNodeInfo(ctx context.Context,
6930
        in *lnrpc.NodeInfoRequest) (*lnrpc.NodeInfo, error) {
×
6931

×
6932
        graph := r.server.graphDB
×
6933

×
6934
        // First, parse the hex-encoded public key into a full in-memory public
×
6935
        // key object we can work with for querying.
×
6936
        pubKey, err := route.NewVertexFromStr(in.PubKey)
×
6937
        if err != nil {
×
6938
                return nil, err
×
6939
        }
×
6940

6941
        // With the public key decoded, attempt to fetch the node corresponding
6942
        // to this public key. If the node cannot be found, then an error will
6943
        // be returned.
6944
        node, err := graph.FetchLightningNode(pubKey)
×
6945
        switch {
×
6946
        case errors.Is(err, graphdb.ErrGraphNodeNotFound):
×
6947
                return nil, status.Error(codes.NotFound, err.Error())
×
6948
        case err != nil:
×
6949
                return nil, err
×
6950
        }
6951

6952
        // With the node obtained, we'll now iterate through all its out going
6953
        // edges to gather some basic statistics about its out going channels.
6954
        var (
×
6955
                numChannels   uint32
×
6956
                totalCapacity btcutil.Amount
×
6957
                channels      []*lnrpc.ChannelEdge
×
6958
        )
×
6959

×
6960
        err = graph.ForEachNodeChannel(node.PubKeyBytes,
×
NEW
6961
                func(edge *models.ChannelEdgeInfo,
×
6962
                        c1, c2 *models.ChannelEdgePolicy) error {
×
6963

×
6964
                        numChannels++
×
6965
                        totalCapacity += edge.Capacity
×
6966

×
6967
                        // Only populate the node's channels if the user
×
6968
                        // requested them.
×
6969
                        if in.IncludeChannels {
×
6970
                                // Do not include unannounced channels - private
×
6971
                                // channels or public channels whose
×
6972
                                // authentication proof were not confirmed yet.
×
6973
                                if edge.AuthProof == nil {
×
6974
                                        return nil
×
6975
                                }
×
6976

6977
                                // Convert the database's edge format into the
6978
                                // network/RPC edge format.
6979
                                channelEdge := marshalDBEdge(edge, c1, c2)
×
6980
                                channels = append(channels, channelEdge)
×
6981
                        }
6982

6983
                        return nil
×
6984
                },
6985
        )
6986
        if err != nil {
×
6987
                return nil, err
×
6988
        }
×
6989

6990
        return &lnrpc.NodeInfo{
×
6991
                Node:          marshalNode(node),
×
6992
                NumChannels:   numChannels,
×
6993
                TotalCapacity: int64(totalCapacity),
×
6994
                Channels:      channels,
×
6995
        }, nil
×
6996
}
6997

6998
func marshalNode(node *models.LightningNode) *lnrpc.LightningNode {
3✔
6999
        nodeAddrs := make([]*lnrpc.NodeAddress, len(node.Addresses))
3✔
7000
        for i, addr := range node.Addresses {
6✔
7001
                nodeAddr := &lnrpc.NodeAddress{
3✔
7002
                        Network: addr.Network(),
3✔
7003
                        Addr:    addr.String(),
3✔
7004
                }
3✔
7005
                nodeAddrs[i] = nodeAddr
3✔
7006
        }
3✔
7007

7008
        features := invoicesrpc.CreateRPCFeatures(node.Features)
3✔
7009

3✔
7010
        customRecords := marshalExtraOpaqueData(node.ExtraOpaqueData)
3✔
7011

3✔
7012
        return &lnrpc.LightningNode{
3✔
7013
                LastUpdate:    uint32(node.LastUpdate.Unix()),
3✔
7014
                PubKey:        hex.EncodeToString(node.PubKeyBytes[:]),
3✔
7015
                Addresses:     nodeAddrs,
3✔
7016
                Alias:         node.Alias,
3✔
7017
                Color:         graphdb.EncodeHexColor(node.Color),
3✔
7018
                Features:      features,
3✔
7019
                CustomRecords: customRecords,
3✔
7020
        }
3✔
7021
}
7022

7023
// QueryRoutes attempts to query the daemons' Channel Router for a possible
7024
// route to a target destination capable of carrying a specific amount of
7025
// satoshis within the route's flow. The returned route contains the full
7026
// details required to craft and send an HTLC, also including the necessary
7027
// information that should be present within the Sphinx packet encapsulated
7028
// within the HTLC.
7029
//
7030
// TODO(roasbeef): should return a slice of routes in reality
7031
//   - create separate PR to send based on well formatted route
7032
func (r *rpcServer) QueryRoutes(ctx context.Context,
7033
        in *lnrpc.QueryRoutesRequest) (*lnrpc.QueryRoutesResponse, error) {
3✔
7034

3✔
7035
        return r.routerBackend.QueryRoutes(ctx, in)
3✔
7036
}
3✔
7037

7038
// GetNetworkInfo returns some basic stats about the known channel graph from
7039
// the PoV of the node.
7040
func (r *rpcServer) GetNetworkInfo(ctx context.Context,
7041
        _ *lnrpc.NetworkInfoRequest) (*lnrpc.NetworkInfo, error) {
×
7042

×
7043
        graph := r.server.graphDB
×
7044

×
7045
        var (
×
7046
                numNodes             uint32
×
7047
                numChannels          uint32
×
7048
                maxChanOut           uint32
×
7049
                totalNetworkCapacity btcutil.Amount
×
7050
                minChannelSize       btcutil.Amount = math.MaxInt64
×
7051
                maxChannelSize       btcutil.Amount
×
7052
                medianChanSize       btcutil.Amount
×
7053
        )
×
7054

×
7055
        // We'll use this map to de-duplicate channels during our traversal.
×
7056
        // This is needed since channels are directional, so there will be two
×
7057
        // edges for each channel within the graph.
×
7058
        seenChans := make(map[uint64]struct{})
×
7059

×
7060
        // We also keep a list of all encountered capacities, in order to
×
7061
        // calculate the median channel size.
×
7062
        var allChans []btcutil.Amount
×
7063

×
7064
        // We'll run through all the known nodes in the within our view of the
×
7065
        // network, tallying up the total number of nodes, and also gathering
×
7066
        // each node so we can measure the graph diameter and degree stats
×
7067
        // below.
×
7068
        err := graph.ForEachNodeCached(func(node route.Vertex,
×
7069
                edges map[uint64]*graphdb.DirectedChannel) error {
×
7070

×
7071
                // Increment the total number of nodes with each iteration.
×
7072
                numNodes++
×
7073

×
7074
                // For each channel we'll compute the out degree of each node,
×
7075
                // and also update our running tallies of the min/max channel
×
7076
                // capacity, as well as the total channel capacity. We pass
×
7077
                // through the db transaction from the outer view so we can
×
7078
                // re-use it within this inner view.
×
7079
                var outDegree uint32
×
7080
                for _, edge := range edges {
×
7081
                        // Bump up the out degree for this node for each
×
7082
                        // channel encountered.
×
7083
                        outDegree++
×
7084

×
7085
                        // If we've already seen this channel, then we'll
×
7086
                        // return early to ensure that we don't double-count
×
7087
                        // stats.
×
7088
                        if _, ok := seenChans[edge.ChannelID]; ok {
×
7089
                                return nil
×
7090
                        }
×
7091

7092
                        // Compare the capacity of this channel against the
7093
                        // running min/max to see if we should update the
7094
                        // extrema.
7095
                        chanCapacity := edge.Capacity
×
7096
                        if chanCapacity < minChannelSize {
×
7097
                                minChannelSize = chanCapacity
×
7098
                        }
×
7099
                        if chanCapacity > maxChannelSize {
×
7100
                                maxChannelSize = chanCapacity
×
7101
                        }
×
7102

7103
                        // Accumulate the total capacity of this channel to the
7104
                        // network wide-capacity.
7105
                        totalNetworkCapacity += chanCapacity
×
7106

×
7107
                        numChannels++
×
7108

×
7109
                        seenChans[edge.ChannelID] = struct{}{}
×
7110
                        allChans = append(allChans, edge.Capacity)
×
7111
                }
7112

7113
                // Finally, if the out degree of this node is greater than what
7114
                // we've seen so far, update the maxChanOut variable.
7115
                if outDegree > maxChanOut {
×
7116
                        maxChanOut = outDegree
×
7117
                }
×
7118

7119
                return nil
×
7120
        })
7121
        if err != nil {
×
7122
                return nil, err
×
7123
        }
×
7124

7125
        // Query the graph for the current number of zombie channels.
7126
        numZombies, err := graph.NumZombies()
×
7127
        if err != nil {
×
7128
                return nil, err
×
7129
        }
×
7130

7131
        // Find the median.
7132
        medianChanSize = autopilot.Median(allChans)
×
7133

×
7134
        // If we don't have any channels, then reset the minChannelSize to zero
×
7135
        // to avoid outputting NaN in encoded JSON.
×
7136
        if numChannels == 0 {
×
7137
                minChannelSize = 0
×
7138
        }
×
7139

7140
        // Graph diameter.
7141
        channelGraph := autopilot.ChannelGraphFromCachedDatabase(graph)
×
NEW
7142
        simpleGraph, err := autopilot.NewSimpleGraph(ctx, channelGraph)
×
7143
        if err != nil {
×
7144
                return nil, err
×
7145
        }
×
7146
        start := time.Now()
×
7147
        diameter := simpleGraph.DiameterRadialCutoff()
×
7148
        rpcsLog.Infof("elapsed time for diameter (%d) calculation: %v", diameter,
×
7149
                time.Since(start))
×
7150

×
7151
        // TODO(roasbeef): also add oldest channel?
×
7152
        netInfo := &lnrpc.NetworkInfo{
×
7153
                GraphDiameter:        diameter,
×
7154
                MaxOutDegree:         maxChanOut,
×
7155
                AvgOutDegree:         float64(2*numChannels) / float64(numNodes),
×
7156
                NumNodes:             numNodes,
×
7157
                NumChannels:          numChannels,
×
7158
                TotalNetworkCapacity: int64(totalNetworkCapacity),
×
7159
                AvgChannelSize:       float64(totalNetworkCapacity) / float64(numChannels),
×
7160

×
7161
                MinChannelSize:       int64(minChannelSize),
×
7162
                MaxChannelSize:       int64(maxChannelSize),
×
7163
                MedianChannelSizeSat: int64(medianChanSize),
×
7164
                NumZombieChans:       numZombies,
×
7165
        }
×
7166

×
7167
        // Similarly, if we don't have any channels, then we'll also set the
×
7168
        // average channel size to zero in order to avoid weird JSON encoding
×
7169
        // outputs.
×
7170
        if numChannels == 0 {
×
7171
                netInfo.AvgChannelSize = 0
×
7172
        }
×
7173

7174
        return netInfo, nil
×
7175
}
7176

7177
// StopDaemon will send a shutdown request to the interrupt handler, triggering
7178
// a graceful shutdown of the daemon.
7179
func (r *rpcServer) StopDaemon(_ context.Context,
7180
        _ *lnrpc.StopRequest) (*lnrpc.StopResponse, error) {
3✔
7181

3✔
7182
        // Before we even consider a shutdown, are we currently in recovery
3✔
7183
        // mode? We don't want to allow shutting down during recovery because
3✔
7184
        // that would mean the user would have to manually continue the rescan
3✔
7185
        // process next time by using `lncli unlock --recovery_window X`
3✔
7186
        // otherwise some funds wouldn't be picked up.
3✔
7187
        isRecoveryMode, progress, err := r.server.cc.Wallet.GetRecoveryInfo()
3✔
7188
        if err != nil {
3✔
7189
                return nil, fmt.Errorf("unable to get wallet recovery info: %w",
×
7190
                        err)
×
7191
        }
×
7192
        if isRecoveryMode && progress < 1 {
3✔
7193
                return nil, fmt.Errorf("wallet recovery in progress, cannot " +
×
7194
                        "shut down, please wait until rescan finishes")
×
7195
        }
×
7196

7197
        r.interceptor.RequestShutdown()
3✔
7198

3✔
7199
        return &lnrpc.StopResponse{
3✔
7200
                Status: "shutdown initiated, check logs for progress",
3✔
7201
        }, nil
3✔
7202
}
7203

7204
// SubscribeChannelGraph launches a streaming RPC that allows the caller to
7205
// receive notifications upon any changes the channel graph topology from the
7206
// review of the responding node. Events notified include: new nodes coming
7207
// online, nodes updating their authenticated attributes, new channels being
7208
// advertised, updates in the routing policy for a directional channel edge,
7209
// and finally when prior channels are closed on-chain.
7210
func (r *rpcServer) SubscribeChannelGraph(req *lnrpc.GraphTopologySubscription,
7211
        updateStream lnrpc.Lightning_SubscribeChannelGraphServer) error {
3✔
7212

3✔
7213
        // First, we start by subscribing to a new intent to receive
3✔
7214
        // notifications from the channel router.
3✔
7215
        client, err := r.server.graphDB.SubscribeTopology()
3✔
7216
        if err != nil {
3✔
7217
                return err
×
7218
        }
×
7219

7220
        // Ensure that the resources for the topology update client is cleaned
7221
        // up once either the server, or client exists.
7222
        defer client.Cancel()
3✔
7223

3✔
7224
        for {
6✔
7225
                select {
3✔
7226

7227
                // A new update has been sent by the channel router, we'll
7228
                // marshal it into the form expected by the gRPC client, then
7229
                // send it off.
7230
                case topChange, ok := <-client.TopologyChanges:
3✔
7231
                        // If the second value from the channel read is nil,
3✔
7232
                        // then this means that the channel router is exiting
3✔
7233
                        // or the notification client was canceled. So we'll
3✔
7234
                        // exit early.
3✔
7235
                        if !ok {
3✔
7236
                                return errors.New("server shutting down")
×
7237
                        }
×
7238

7239
                        // Convert the struct from the channel router into the
7240
                        // form expected by the gRPC service then send it off
7241
                        // to the client.
7242
                        graphUpdate := marshallTopologyChange(topChange)
3✔
7243
                        if err := updateStream.Send(graphUpdate); err != nil {
3✔
7244
                                return err
×
7245
                        }
×
7246

7247
                // The response stream's context for whatever reason has been
7248
                // closed. If context is closed by an exceeded deadline
7249
                // we will return an error.
7250
                case <-updateStream.Context().Done():
3✔
7251
                        if errors.Is(updateStream.Context().Err(), context.Canceled) {
6✔
7252
                                return nil
3✔
7253
                        }
3✔
7254
                        return updateStream.Context().Err()
×
7255

7256
                // The server is quitting, so we'll exit immediately. Returning
7257
                // nil will close the clients read end of the stream.
7258
                case <-r.quit:
×
7259
                        return nil
×
7260
                }
7261
        }
7262
}
7263

7264
// marshallTopologyChange performs a mapping from the topology change struct
7265
// returned by the router to the form of notifications expected by the current
7266
// gRPC service.
7267
func marshallTopologyChange(
7268
        topChange *graphdb.TopologyChange) *lnrpc.GraphTopologyUpdate {
3✔
7269

3✔
7270
        // encodeKey is a simple helper function that converts a live public
3✔
7271
        // key into a hex-encoded version of the compressed serialization for
3✔
7272
        // the public key.
3✔
7273
        encodeKey := func(k *btcec.PublicKey) string {
6✔
7274
                return hex.EncodeToString(k.SerializeCompressed())
3✔
7275
        }
3✔
7276

7277
        nodeUpdates := make([]*lnrpc.NodeUpdate, len(topChange.NodeUpdates))
3✔
7278
        for i, nodeUpdate := range topChange.NodeUpdates {
6✔
7279
                nodeAddrs := make(
3✔
7280
                        []*lnrpc.NodeAddress, 0, len(nodeUpdate.Addresses),
3✔
7281
                )
3✔
7282
                for _, addr := range nodeUpdate.Addresses {
6✔
7283
                        nodeAddr := &lnrpc.NodeAddress{
3✔
7284
                                Network: addr.Network(),
3✔
7285
                                Addr:    addr.String(),
3✔
7286
                        }
3✔
7287
                        nodeAddrs = append(nodeAddrs, nodeAddr)
3✔
7288
                }
3✔
7289

7290
                addrs := make([]string, len(nodeUpdate.Addresses))
3✔
7291
                for i, addr := range nodeUpdate.Addresses {
6✔
7292
                        addrs[i] = addr.String()
3✔
7293
                }
3✔
7294

7295
                nodeUpdates[i] = &lnrpc.NodeUpdate{
3✔
7296
                        Addresses:     addrs,
3✔
7297
                        NodeAddresses: nodeAddrs,
3✔
7298
                        IdentityKey:   encodeKey(nodeUpdate.IdentityKey),
3✔
7299
                        Alias:         nodeUpdate.Alias,
3✔
7300
                        Color:         nodeUpdate.Color,
3✔
7301
                        Features: invoicesrpc.CreateRPCFeatures(
3✔
7302
                                nodeUpdate.Features,
3✔
7303
                        ),
3✔
7304
                }
3✔
7305
        }
7306

7307
        channelUpdates := make([]*lnrpc.ChannelEdgeUpdate, len(topChange.ChannelEdgeUpdates))
3✔
7308
        for i, channelUpdate := range topChange.ChannelEdgeUpdates {
6✔
7309

3✔
7310
                customRecords := marshalExtraOpaqueData(
3✔
7311
                        channelUpdate.ExtraOpaqueData,
3✔
7312
                )
3✔
7313
                inboundFee := extractInboundFeeSafe(
3✔
7314
                        channelUpdate.ExtraOpaqueData,
3✔
7315
                )
3✔
7316

3✔
7317
                channelUpdates[i] = &lnrpc.ChannelEdgeUpdate{
3✔
7318
                        ChanId: channelUpdate.ChanID,
3✔
7319
                        ChanPoint: &lnrpc.ChannelPoint{
3✔
7320
                                FundingTxid: &lnrpc.ChannelPoint_FundingTxidBytes{
3✔
7321
                                        FundingTxidBytes: channelUpdate.ChanPoint.Hash[:],
3✔
7322
                                },
3✔
7323
                                OutputIndex: channelUpdate.ChanPoint.Index,
3✔
7324
                        },
3✔
7325
                        Capacity: int64(channelUpdate.Capacity),
3✔
7326
                        RoutingPolicy: &lnrpc.RoutingPolicy{
3✔
7327
                                TimeLockDelta: uint32(
3✔
7328
                                        channelUpdate.TimeLockDelta,
3✔
7329
                                ),
3✔
7330
                                MinHtlc: int64(
3✔
7331
                                        channelUpdate.MinHTLC,
3✔
7332
                                ),
3✔
7333
                                MaxHtlcMsat: uint64(
3✔
7334
                                        channelUpdate.MaxHTLC,
3✔
7335
                                ),
3✔
7336
                                FeeBaseMsat: int64(
3✔
7337
                                        channelUpdate.BaseFee,
3✔
7338
                                ),
3✔
7339
                                FeeRateMilliMsat: int64(
3✔
7340
                                        channelUpdate.FeeRate,
3✔
7341
                                ),
3✔
7342
                                Disabled:                channelUpdate.Disabled,
3✔
7343
                                InboundFeeBaseMsat:      inboundFee.BaseFee,
3✔
7344
                                InboundFeeRateMilliMsat: inboundFee.FeeRate,
3✔
7345
                                CustomRecords:           customRecords,
3✔
7346
                        },
3✔
7347
                        AdvertisingNode: encodeKey(channelUpdate.AdvertisingNode),
3✔
7348
                        ConnectingNode:  encodeKey(channelUpdate.ConnectingNode),
3✔
7349
                }
3✔
7350
        }
3✔
7351

7352
        closedChans := make([]*lnrpc.ClosedChannelUpdate, len(topChange.ClosedChannels))
3✔
7353
        for i, closedChan := range topChange.ClosedChannels {
6✔
7354
                closedChans[i] = &lnrpc.ClosedChannelUpdate{
3✔
7355
                        ChanId:       closedChan.ChanID,
3✔
7356
                        Capacity:     int64(closedChan.Capacity),
3✔
7357
                        ClosedHeight: closedChan.ClosedHeight,
3✔
7358
                        ChanPoint: &lnrpc.ChannelPoint{
3✔
7359
                                FundingTxid: &lnrpc.ChannelPoint_FundingTxidBytes{
3✔
7360
                                        FundingTxidBytes: closedChan.ChanPoint.Hash[:],
3✔
7361
                                },
3✔
7362
                                OutputIndex: closedChan.ChanPoint.Index,
3✔
7363
                        },
3✔
7364
                }
3✔
7365
        }
3✔
7366

7367
        return &lnrpc.GraphTopologyUpdate{
3✔
7368
                NodeUpdates:    nodeUpdates,
3✔
7369
                ChannelUpdates: channelUpdates,
3✔
7370
                ClosedChans:    closedChans,
3✔
7371
        }
3✔
7372
}
7373

7374
// ListPayments returns a list of outgoing payments determined by a paginated
7375
// database query.
7376
func (r *rpcServer) ListPayments(ctx context.Context,
7377
        req *lnrpc.ListPaymentsRequest) (*lnrpc.ListPaymentsResponse, error) {
3✔
7378

3✔
7379
        // If both dates are set, we check that the start date is less than the
3✔
7380
        // end date, otherwise we'll get an empty result.
3✔
7381
        if req.CreationDateStart != 0 && req.CreationDateEnd != 0 {
3✔
7382
                if req.CreationDateStart >= req.CreationDateEnd {
×
7383
                        return nil, fmt.Errorf("start date(%v) must be before "+
×
7384
                                "end date(%v)", req.CreationDateStart,
×
7385
                                req.CreationDateEnd)
×
7386
                }
×
7387
        }
7388

7389
        query := channeldb.PaymentsQuery{
3✔
7390
                IndexOffset:       req.IndexOffset,
3✔
7391
                MaxPayments:       req.MaxPayments,
3✔
7392
                Reversed:          req.Reversed,
3✔
7393
                IncludeIncomplete: req.IncludeIncomplete,
3✔
7394
                CountTotal:        req.CountTotalPayments,
3✔
7395
                CreationDateStart: int64(req.CreationDateStart),
3✔
7396
                CreationDateEnd:   int64(req.CreationDateEnd),
3✔
7397
        }
3✔
7398

3✔
7399
        // If the maximum number of payments wasn't specified, then we'll
3✔
7400
        // default to return the maximal number of payments representable.
3✔
7401
        if req.MaxPayments == 0 {
6✔
7402
                query.MaxPayments = math.MaxUint64
3✔
7403
        }
3✔
7404

7405
        paymentsQuerySlice, err := r.server.miscDB.QueryPayments(query)
3✔
7406
        if err != nil {
3✔
7407
                return nil, err
×
7408
        }
×
7409

7410
        paymentsResp := &lnrpc.ListPaymentsResponse{
3✔
7411
                LastIndexOffset:  paymentsQuerySlice.LastIndexOffset,
3✔
7412
                FirstIndexOffset: paymentsQuerySlice.FirstIndexOffset,
3✔
7413
                TotalNumPayments: paymentsQuerySlice.TotalCount,
3✔
7414
        }
3✔
7415

3✔
7416
        for _, payment := range paymentsQuerySlice.Payments {
6✔
7417
                payment := payment
3✔
7418

3✔
7419
                rpcPayment, err := r.routerBackend.MarshallPayment(payment)
3✔
7420
                if err != nil {
3✔
7421
                        return nil, err
×
7422
                }
×
7423

7424
                paymentsResp.Payments = append(
3✔
7425
                        paymentsResp.Payments, rpcPayment,
3✔
7426
                )
3✔
7427
        }
7428

7429
        return paymentsResp, nil
3✔
7430
}
7431

7432
// DeletePayment deletes a payment from the DB given its payment hash. If
7433
// failedHtlcsOnly is set, only failed HTLC attempts of the payment will be
7434
// deleted.
7435
func (r *rpcServer) DeletePayment(ctx context.Context,
7436
        req *lnrpc.DeletePaymentRequest) (
7437
        *lnrpc.DeletePaymentResponse, error) {
×
7438

×
7439
        hash, err := lntypes.MakeHash(req.PaymentHash)
×
7440
        if err != nil {
×
7441
                return nil, err
×
7442
        }
×
7443

7444
        rpcsLog.Infof("[DeletePayment] payment_identifier=%v, "+
×
7445
                "failed_htlcs_only=%v", hash, req.FailedHtlcsOnly)
×
7446

×
7447
        err = r.server.miscDB.DeletePayment(hash, req.FailedHtlcsOnly)
×
7448
        if err != nil {
×
7449
                return nil, err
×
7450
        }
×
7451

7452
        return &lnrpc.DeletePaymentResponse{
×
7453
                Status: "payment deleted",
×
7454
        }, nil
×
7455
}
7456

7457
// DeleteAllPayments deletes all outgoing payments from DB.
7458
func (r *rpcServer) DeleteAllPayments(ctx context.Context,
7459
        req *lnrpc.DeleteAllPaymentsRequest) (
7460
        *lnrpc.DeleteAllPaymentsResponse, error) {
3✔
7461

3✔
7462
        switch {
3✔
7463
        // Since this is a destructive operation, at least one of the options
7464
        // must be set to true.
7465
        case !req.AllPayments && !req.FailedPaymentsOnly &&
7466
                !req.FailedHtlcsOnly:
×
7467

×
7468
                return nil, fmt.Errorf("at least one of the options " +
×
7469
                        "`all_payments`, `failed_payments_only`, or " +
×
7470
                        "`failed_htlcs_only` must be set to true")
×
7471

7472
        // `all_payments` cannot be true with `failed_payments_only` or
7473
        // `failed_htlcs_only`. `all_payments` includes all records, making
7474
        // these options contradictory.
7475
        case req.AllPayments &&
7476
                (req.FailedPaymentsOnly || req.FailedHtlcsOnly):
×
7477

×
7478
                return nil, fmt.Errorf("`all_payments` cannot be set to true " +
×
7479
                        "while either `failed_payments_only` or " +
×
7480
                        "`failed_htlcs_only` is also set to true")
×
7481
        }
7482

7483
        rpcsLog.Infof("[DeleteAllPayments] failed_payments_only=%v, "+
3✔
7484
                "failed_htlcs_only=%v", req.FailedPaymentsOnly,
3✔
7485
                req.FailedHtlcsOnly)
3✔
7486

3✔
7487
        numDeletedPayments, err := r.server.miscDB.DeletePayments(
3✔
7488
                req.FailedPaymentsOnly, req.FailedHtlcsOnly,
3✔
7489
        )
3✔
7490
        if err != nil {
3✔
7491
                return nil, err
×
7492
        }
×
7493

7494
        return &lnrpc.DeleteAllPaymentsResponse{
3✔
7495
                Status: fmt.Sprintf("%v payments deleted, failed_htlcs_only=%v",
3✔
7496
                        numDeletedPayments, req.FailedHtlcsOnly),
3✔
7497
        }, nil
3✔
7498
}
7499

7500
// DebugLevel allows a caller to programmatically set the logging verbosity of
7501
// lnd. The logging can be targeted according to a coarse daemon-wide logging
7502
// level, or in a granular fashion to specify the logging for a target
7503
// sub-system.
7504
func (r *rpcServer) DebugLevel(ctx context.Context,
7505
        req *lnrpc.DebugLevelRequest) (*lnrpc.DebugLevelResponse, error) {
×
7506

×
7507
        // If show is set, then we simply print out the list of available
×
7508
        // sub-systems.
×
7509
        if req.Show {
×
7510
                return &lnrpc.DebugLevelResponse{
×
7511
                        SubSystems: strings.Join(
×
7512
                                r.cfg.SubLogMgr.SupportedSubsystems(), " ",
×
7513
                        ),
×
7514
                }, nil
×
7515
        }
×
7516

7517
        rpcsLog.Infof("[debuglevel] changing debug level to: %v", req.LevelSpec)
×
7518

×
7519
        // Otherwise, we'll attempt to set the logging level using the
×
7520
        // specified level spec.
×
7521
        err := build.ParseAndSetDebugLevels(req.LevelSpec, r.cfg.SubLogMgr)
×
7522
        if err != nil {
×
7523
                return nil, err
×
7524
        }
×
7525

7526
        subLoggers := r.cfg.SubLogMgr.SubLoggers()
×
7527
        // Sort alphabetically by subsystem name.
×
7528
        var tags []string
×
7529
        for t := range subLoggers {
×
7530
                tags = append(tags, t)
×
7531
        }
×
7532
        sort.Strings(tags)
×
7533

×
7534
        // Create the log levels string.
×
7535
        var logLevels []string
×
7536
        for _, t := range tags {
×
7537
                logLevels = append(logLevels, fmt.Sprintf("%s=%s", t,
×
7538
                        subLoggers[t].Level().String()))
×
7539
        }
×
7540
        logLevelsString := strings.Join(logLevels, ", ")
×
7541

×
7542
        // Propagate the new config level to the main config struct.
×
7543
        r.cfg.DebugLevel = logLevelsString
×
7544

×
7545
        return &lnrpc.DebugLevelResponse{
×
7546
                SubSystems: logLevelsString,
×
7547
        }, nil
×
7548
}
7549

7550
// DecodePayReq takes an encoded payment request string and attempts to decode
7551
// it, returning a full description of the conditions encoded within the
7552
// payment request.
7553
func (r *rpcServer) DecodePayReq(ctx context.Context,
7554
        req *lnrpc.PayReqString) (*lnrpc.PayReq, error) {
3✔
7555

3✔
7556
        rpcsLog.Tracef("[decodepayreq] decoding: %v", req.PayReq)
3✔
7557

3✔
7558
        // Fist we'll attempt to decode the payment request string, if the
3✔
7559
        // request is invalid or the checksum doesn't match, then we'll exit
3✔
7560
        // here with an error.
3✔
7561
        payReq, err := zpay32.Decode(req.PayReq, r.cfg.ActiveNetParams.Params)
3✔
7562
        if err != nil {
3✔
7563
                return nil, err
×
7564
        }
×
7565

7566
        // Let the fields default to empty strings.
7567
        desc := ""
3✔
7568
        if payReq.Description != nil {
6✔
7569
                desc = *payReq.Description
3✔
7570
        }
3✔
7571

7572
        descHash := []byte("")
3✔
7573
        if payReq.DescriptionHash != nil {
3✔
7574
                descHash = payReq.DescriptionHash[:]
×
7575
        }
×
7576

7577
        fallbackAddr := ""
3✔
7578
        if payReq.FallbackAddr != nil {
3✔
7579
                fallbackAddr = payReq.FallbackAddr.String()
×
7580
        }
×
7581

7582
        // Expiry time will default to 3600 seconds if not specified
7583
        // explicitly.
7584
        expiry := int64(payReq.Expiry().Seconds())
3✔
7585

3✔
7586
        // Convert between the `lnrpc` and `routing` types.
3✔
7587
        routeHints := invoicesrpc.CreateRPCRouteHints(payReq.RouteHints)
3✔
7588

3✔
7589
        blindedPaymentPaths, err := invoicesrpc.CreateRPCBlindedPayments(
3✔
7590
                payReq.BlindedPaymentPaths,
3✔
7591
        )
3✔
7592
        if err != nil {
3✔
7593
                return nil, err
×
7594
        }
×
7595

7596
        var amtSat, amtMsat int64
3✔
7597
        if payReq.MilliSat != nil {
6✔
7598
                amtSat = int64(payReq.MilliSat.ToSatoshis())
3✔
7599
                amtMsat = int64(*payReq.MilliSat)
3✔
7600
        }
3✔
7601

7602
        // Extract the payment address from the payment request, if present.
7603
        paymentAddr := payReq.PaymentAddr.UnwrapOr([32]byte{})
3✔
7604

3✔
7605
        dest := payReq.Destination.SerializeCompressed()
3✔
7606
        return &lnrpc.PayReq{
3✔
7607
                Destination:     hex.EncodeToString(dest),
3✔
7608
                PaymentHash:     hex.EncodeToString(payReq.PaymentHash[:]),
3✔
7609
                NumSatoshis:     amtSat,
3✔
7610
                NumMsat:         amtMsat,
3✔
7611
                Timestamp:       payReq.Timestamp.Unix(),
3✔
7612
                Description:     desc,
3✔
7613
                DescriptionHash: hex.EncodeToString(descHash[:]),
3✔
7614
                FallbackAddr:    fallbackAddr,
3✔
7615
                Expiry:          expiry,
3✔
7616
                CltvExpiry:      int64(payReq.MinFinalCLTVExpiry()),
3✔
7617
                RouteHints:      routeHints,
3✔
7618
                BlindedPaths:    blindedPaymentPaths,
3✔
7619
                PaymentAddr:     paymentAddr[:],
3✔
7620
                Features:        invoicesrpc.CreateRPCFeatures(payReq.Features),
3✔
7621
        }, nil
3✔
7622
}
7623

7624
// feeBase is the fixed point that fee rate computation are performed over.
7625
// Nodes on the network advertise their fee rate using this point as a base.
7626
// This means that the minimal possible fee rate if 1e-6, or 0.000001, or
7627
// 0.0001%.
7628
const feeBase float64 = 1000000
7629

7630
// FeeReport allows the caller to obtain a report detailing the current fee
7631
// schedule enforced by the node globally for each channel.
7632
func (r *rpcServer) FeeReport(ctx context.Context,
7633
        _ *lnrpc.FeeReportRequest) (*lnrpc.FeeReportResponse, error) {
3✔
7634

3✔
7635
        channelGraph := r.server.graphDB
3✔
7636
        selfNode, err := channelGraph.SourceNode()
3✔
7637
        if err != nil {
3✔
7638
                return nil, err
×
7639
        }
×
7640

7641
        var feeReports []*lnrpc.ChannelFeeReport
3✔
7642
        err = channelGraph.ForEachNodeChannel(selfNode.PubKeyBytes,
3✔
7643
                func(chanInfo *models.ChannelEdgeInfo,
3✔
7644
                        edgePolicy, _ *models.ChannelEdgePolicy) error {
6✔
7645

3✔
7646
                        // Self node should always have policies for its
3✔
7647
                        // channels.
3✔
7648
                        if edgePolicy == nil {
3✔
7649
                                return fmt.Errorf("no policy for outgoing "+
×
7650
                                        "channel %v ", chanInfo.ChannelID)
×
7651
                        }
×
7652

7653
                        // We'll compute the effective fee rate by converting
7654
                        // from a fixed point fee rate to a floating point fee
7655
                        // rate. The fee rate field in the database the amount
7656
                        // of mSAT charged per 1mil mSAT sent, so will divide by
7657
                        // this to get the proper fee rate.
7658
                        feeRateFixedPoint :=
3✔
7659
                                edgePolicy.FeeProportionalMillionths
3✔
7660
                        feeRate := float64(feeRateFixedPoint) / feeBase
3✔
7661

3✔
7662
                        // Decode inbound fee from extra data.
3✔
7663
                        var inboundFee lnwire.Fee
3✔
7664
                        _, err := edgePolicy.ExtraOpaqueData.ExtractRecords(
3✔
7665
                                &inboundFee,
3✔
7666
                        )
3✔
7667
                        if err != nil {
3✔
7668
                                return err
×
7669
                        }
×
7670

7671
                        // TODO(roasbeef): also add stats for revenue for each
7672
                        // channel
7673
                        feeReports = append(feeReports, &lnrpc.ChannelFeeReport{
3✔
7674
                                ChanId:       chanInfo.ChannelID,
3✔
7675
                                ChannelPoint: chanInfo.ChannelPoint.String(),
3✔
7676
                                BaseFeeMsat:  int64(edgePolicy.FeeBaseMSat),
3✔
7677
                                FeePerMil:    int64(feeRateFixedPoint),
3✔
7678
                                FeeRate:      feeRate,
3✔
7679

3✔
7680
                                InboundBaseFeeMsat: inboundFee.BaseFee,
3✔
7681
                                InboundFeePerMil:   inboundFee.FeeRate,
3✔
7682
                        })
3✔
7683

3✔
7684
                        return nil
3✔
7685
                },
7686
        )
7687
        if err != nil {
3✔
7688
                return nil, err
×
7689
        }
×
7690

7691
        fwdEventLog := r.server.miscDB.ForwardingLog()
3✔
7692

3✔
7693
        // computeFeeSum is a helper function that computes the total fees for
3✔
7694
        // a particular time slice described by a forwarding event query.
3✔
7695
        computeFeeSum := func(query channeldb.ForwardingEventQuery) (lnwire.MilliSatoshi, error) {
6✔
7696

3✔
7697
                var totalFees lnwire.MilliSatoshi
3✔
7698

3✔
7699
                // We'll continue to fetch the next query and accumulate the
3✔
7700
                // fees until the next query returns no events.
3✔
7701
                for {
6✔
7702
                        timeSlice, err := fwdEventLog.Query(query)
3✔
7703
                        if err != nil {
3✔
7704
                                return 0, err
×
7705
                        }
×
7706

7707
                        // If the timeslice is empty, then we'll return as
7708
                        // we've retrieved all the entries in this range.
7709
                        if len(timeSlice.ForwardingEvents) == 0 {
6✔
7710
                                break
3✔
7711
                        }
7712

7713
                        // Otherwise, we'll tally up an accumulate the total
7714
                        // fees for this time slice.
7715
                        for _, event := range timeSlice.ForwardingEvents {
6✔
7716
                                fee := event.AmtIn - event.AmtOut
3✔
7717
                                totalFees += fee
3✔
7718
                        }
3✔
7719

7720
                        // We'll now take the last offset index returned as
7721
                        // part of this response, and modify our query to start
7722
                        // at this index. This has a pagination effect in the
7723
                        // case that our query bounds has more than 100k
7724
                        // entries.
7725
                        query.IndexOffset = timeSlice.LastIndexOffset
3✔
7726
                }
7727

7728
                return totalFees, nil
3✔
7729
        }
7730

7731
        now := time.Now()
3✔
7732

3✔
7733
        // Before we perform the queries below, we'll instruct the switch to
3✔
7734
        // flush any pending events to disk. This ensure we get a complete
3✔
7735
        // snapshot at this particular time.
3✔
7736
        if err := r.server.htlcSwitch.FlushForwardingEvents(); err != nil {
3✔
7737
                return nil, fmt.Errorf("unable to flush forwarding "+
×
7738
                        "events: %v", err)
×
7739
        }
×
7740

7741
        // In addition to returning the current fee schedule for each channel.
7742
        // We'll also perform a series of queries to obtain the total fees
7743
        // earned over the past day, week, and month.
7744
        dayQuery := channeldb.ForwardingEventQuery{
3✔
7745
                StartTime:    now.Add(-time.Hour * 24),
3✔
7746
                EndTime:      now,
3✔
7747
                NumMaxEvents: 1000,
3✔
7748
        }
3✔
7749
        dayFees, err := computeFeeSum(dayQuery)
3✔
7750
        if err != nil {
3✔
7751
                return nil, fmt.Errorf("unable to retrieve day fees: %w", err)
×
7752
        }
×
7753

7754
        weekQuery := channeldb.ForwardingEventQuery{
3✔
7755
                StartTime:    now.Add(-time.Hour * 24 * 7),
3✔
7756
                EndTime:      now,
3✔
7757
                NumMaxEvents: 1000,
3✔
7758
        }
3✔
7759
        weekFees, err := computeFeeSum(weekQuery)
3✔
7760
        if err != nil {
3✔
7761
                return nil, fmt.Errorf("unable to retrieve day fees: %w", err)
×
7762
        }
×
7763

7764
        monthQuery := channeldb.ForwardingEventQuery{
3✔
7765
                StartTime:    now.Add(-time.Hour * 24 * 30),
3✔
7766
                EndTime:      now,
3✔
7767
                NumMaxEvents: 1000,
3✔
7768
        }
3✔
7769
        monthFees, err := computeFeeSum(monthQuery)
3✔
7770
        if err != nil {
3✔
7771
                return nil, fmt.Errorf("unable to retrieve day fees: %w", err)
×
7772
        }
×
7773

7774
        return &lnrpc.FeeReportResponse{
3✔
7775
                ChannelFees: feeReports,
3✔
7776
                DayFeeSum:   uint64(dayFees.ToSatoshis()),
3✔
7777
                WeekFeeSum:  uint64(weekFees.ToSatoshis()),
3✔
7778
                MonthFeeSum: uint64(monthFees.ToSatoshis()),
3✔
7779
        }, nil
3✔
7780
}
7781

7782
// minFeeRate is the smallest permitted fee rate within the network. This is
7783
// derived by the fact that fee rates are computed using a fixed point of
7784
// 1,000,000. As a result, the smallest representable fee rate is 1e-6, or
7785
// 0.000001, or 0.0001%.
7786
const minFeeRate = 1e-6
7787

7788
// UpdateChannelPolicy allows the caller to update the channel forwarding policy
7789
// for all channels globally, or a particular channel.
7790
func (r *rpcServer) UpdateChannelPolicy(ctx context.Context,
7791
        req *lnrpc.PolicyUpdateRequest) (*lnrpc.PolicyUpdateResponse, error) {
3✔
7792

3✔
7793
        var targetChans []wire.OutPoint
3✔
7794
        switch scope := req.Scope.(type) {
3✔
7795
        // If the request is targeting all active channels, then we don't need
7796
        // target any channels by their channel point.
7797
        case *lnrpc.PolicyUpdateRequest_Global:
3✔
7798

7799
        // Otherwise, we're targeting an individual channel by its channel
7800
        // point.
7801
        case *lnrpc.PolicyUpdateRequest_ChanPoint:
3✔
7802
                txid, err := lnrpc.GetChanPointFundingTxid(scope.ChanPoint)
3✔
7803
                if err != nil {
3✔
7804
                        return nil, err
×
7805
                }
×
7806
                targetChans = append(targetChans, wire.OutPoint{
3✔
7807
                        Hash:  *txid,
3✔
7808
                        Index: scope.ChanPoint.OutputIndex,
3✔
7809
                })
3✔
7810
        default:
×
7811
                return nil, fmt.Errorf("unknown scope: %v", scope)
×
7812
        }
7813

7814
        var feeRateFixed uint32
3✔
7815

3✔
7816
        switch {
3✔
7817
        // The request should use either the fee rate in percent, or the new
7818
        // ppm rate, but not both.
7819
        case req.FeeRate != 0 && req.FeeRatePpm != 0:
×
7820
                errMsg := "cannot set both FeeRate and FeeRatePpm at the " +
×
7821
                        "same time"
×
7822

×
7823
                return nil, status.Errorf(codes.InvalidArgument, errMsg)
×
7824

7825
        // If the request is using fee_rate.
7826
        case req.FeeRate != 0:
3✔
7827
                // As a sanity check, if the fee isn't zero, we'll ensure that
3✔
7828
                // the passed fee rate is below 1e-6, or the lowest allowed
3✔
7829
                // non-zero fee rate expressible within the protocol.
3✔
7830
                if req.FeeRate != 0 && req.FeeRate < minFeeRate {
3✔
7831
                        return nil, fmt.Errorf("fee rate of %v is too "+
×
7832
                                "small, min fee rate is %v", req.FeeRate,
×
7833
                                minFeeRate)
×
7834
                }
×
7835

7836
                // We'll also need to convert the floating point fee rate we
7837
                // accept over RPC to the fixed point rate that we use within
7838
                // the protocol. We do this by multiplying the passed fee rate
7839
                // by the fee base. This gives us the fixed point, scaled by 1
7840
                // million that's used within the protocol.
7841
                //
7842
                // Because of the inaccurate precision of the IEEE 754
7843
                // standard, we need to round the product of feerate and
7844
                // feebase.
7845
                feeRateFixed = uint32(math.Round(req.FeeRate * feeBase))
3✔
7846

7847
        // Otherwise, we use the fee_rate_ppm parameter.
7848
        case req.FeeRatePpm != 0:
3✔
7849
                feeRateFixed = req.FeeRatePpm
3✔
7850
        }
7851

7852
        // We'll also ensure that the user isn't setting a CLTV delta that
7853
        // won't give outgoing HTLCs enough time to fully resolve if needed.
7854
        if req.TimeLockDelta < minTimeLockDelta {
3✔
7855
                return nil, fmt.Errorf("time lock delta of %v is too small, "+
×
7856
                        "minimum supported is %v", req.TimeLockDelta,
×
7857
                        minTimeLockDelta)
×
7858
        } else if req.TimeLockDelta > uint32(MaxTimeLockDelta) {
3✔
7859
                return nil, fmt.Errorf("time lock delta of %v is too big, "+
×
7860
                        "maximum supported is %v", req.TimeLockDelta,
×
7861
                        MaxTimeLockDelta)
×
7862
        }
×
7863

7864
        // By default, positive inbound fees are rejected.
7865
        if !r.cfg.AcceptPositiveInboundFees && req.InboundFee != nil {
6✔
7866
                if req.InboundFee.BaseFeeMsat > 0 {
3✔
7867
                        return nil, fmt.Errorf("positive values for inbound "+
×
7868
                                "base fee msat are not supported: %v",
×
7869
                                req.InboundFee.BaseFeeMsat)
×
7870
                }
×
7871
                if req.InboundFee.FeeRatePpm > 0 {
3✔
7872
                        return nil, fmt.Errorf("positive values for inbound "+
×
7873
                                "fee rate ppm are not supported: %v",
×
7874
                                req.InboundFee.FeeRatePpm)
×
7875
                }
×
7876
        }
7877

7878
        // If no inbound fees have been specified, we indicate with an empty
7879
        // option that the previous inbound fee should be retained during the
7880
        // edge update.
7881
        inboundFee := fn.None[models.InboundFee]()
3✔
7882
        if req.InboundFee != nil {
6✔
7883
                inboundFee = fn.Some(models.InboundFee{
3✔
7884
                        Base: req.InboundFee.BaseFeeMsat,
3✔
7885
                        Rate: req.InboundFee.FeeRatePpm,
3✔
7886
                })
3✔
7887
        }
3✔
7888

7889
        baseFeeMsat := lnwire.MilliSatoshi(req.BaseFeeMsat)
3✔
7890
        feeSchema := routing.FeeSchema{
3✔
7891
                BaseFee:    baseFeeMsat,
3✔
7892
                FeeRate:    feeRateFixed,
3✔
7893
                InboundFee: inboundFee,
3✔
7894
        }
3✔
7895

3✔
7896
        maxHtlc := lnwire.MilliSatoshi(req.MaxHtlcMsat)
3✔
7897
        var minHtlc *lnwire.MilliSatoshi
3✔
7898
        if req.MinHtlcMsatSpecified {
3✔
7899
                min := lnwire.MilliSatoshi(req.MinHtlcMsat)
×
7900
                minHtlc = &min
×
7901
        }
×
7902

7903
        chanPolicy := routing.ChannelPolicy{
3✔
7904
                FeeSchema:     feeSchema,
3✔
7905
                TimeLockDelta: req.TimeLockDelta,
3✔
7906
                MaxHTLC:       maxHtlc,
3✔
7907
                MinHTLC:       minHtlc,
3✔
7908
        }
3✔
7909

3✔
7910
        rpcsLog.Debugf("[updatechanpolicy] updating channel policy "+
3✔
7911
                "base_fee=%v, rate_fixed=%v, time_lock_delta: %v, "+
3✔
7912
                "min_htlc=%v, max_htlc=%v, targets=%v",
3✔
7913
                req.BaseFeeMsat, feeRateFixed, req.TimeLockDelta,
3✔
7914
                minHtlc, maxHtlc,
3✔
7915
                spew.Sdump(targetChans))
3✔
7916

3✔
7917
        // With the scope resolved, we'll now send this to the local channel
3✔
7918
        // manager so it can propagate the new policy for our target channel(s).
3✔
7919
        failedUpdates, err := r.server.localChanMgr.UpdatePolicy(chanPolicy,
3✔
7920
                req.CreateMissingEdge, targetChans...)
3✔
7921
        if err != nil {
3✔
7922
                return nil, err
×
7923
        }
×
7924

7925
        return &lnrpc.PolicyUpdateResponse{
3✔
7926
                FailedUpdates: failedUpdates,
3✔
7927
        }, nil
3✔
7928
}
7929

7930
// ForwardingHistory allows the caller to query the htlcswitch for a record of
7931
// all HTLC's forwarded within the target time range, and integer offset within
7932
// that time range. If no time-range is specified, then the first chunk of the
7933
// past 24 hrs of forwarding history are returned.
7934

7935
// A list of forwarding events are returned. The size of each forwarding event
7936
// is 40 bytes, and the max message size able to be returned in gRPC is 4 MiB.
7937
// In order to safely stay under this max limit, we'll return 50k events per
7938
// response.  Each response has the index offset of the last entry. The index
7939
// offset can be provided to the request to allow the caller to skip a series
7940
// of records.
7941
func (r *rpcServer) ForwardingHistory(ctx context.Context,
7942
        req *lnrpc.ForwardingHistoryRequest) (*lnrpc.ForwardingHistoryResponse,
7943
        error) {
3✔
7944

3✔
7945
        // Before we perform the queries below, we'll instruct the switch to
3✔
7946
        // flush any pending events to disk. This ensure we get a complete
3✔
7947
        // snapshot at this particular time.
3✔
7948
        if err := r.server.htlcSwitch.FlushForwardingEvents(); err != nil {
3✔
7949
                return nil, fmt.Errorf("unable to flush forwarding "+
×
7950
                        "events: %v", err)
×
7951
        }
×
7952

7953
        var (
3✔
7954
                startTime, endTime time.Time
3✔
7955

3✔
7956
                numEvents uint32
3✔
7957
        )
3✔
7958

3✔
7959
        // startTime defaults to the Unix epoch (0 unixtime, or
3✔
7960
        // midnight 01-01-1970).
3✔
7961
        startTime = time.Unix(int64(req.StartTime), 0)
3✔
7962

3✔
7963
        // If the end time wasn't specified, assume a default end time of now.
3✔
7964
        if req.EndTime == 0 {
6✔
7965
                now := time.Now()
3✔
7966
                endTime = now
3✔
7967
        } else {
3✔
7968
                endTime = time.Unix(int64(req.EndTime), 0)
×
7969
        }
×
7970

7971
        // If the number of events wasn't specified, then we'll default to
7972
        // returning the last 100 events.
7973
        numEvents = req.NumMaxEvents
3✔
7974
        if numEvents == 0 {
6✔
7975
                numEvents = 100
3✔
7976
        }
3✔
7977

7978
        // Next, we'll map the proto request into a format that is understood by
7979
        // the forwarding log.
7980
        eventQuery := channeldb.ForwardingEventQuery{
3✔
7981
                StartTime:    startTime,
3✔
7982
                EndTime:      endTime,
3✔
7983
                IndexOffset:  req.IndexOffset,
3✔
7984
                NumMaxEvents: numEvents,
3✔
7985
        }
3✔
7986
        timeSlice, err := r.server.miscDB.ForwardingLog().Query(eventQuery)
3✔
7987
        if err != nil {
3✔
7988
                return nil, fmt.Errorf("unable to query forwarding log: %w",
×
7989
                        err)
×
7990
        }
×
7991

7992
        // chanToPeerAlias caches previously looked up channel information.
7993
        chanToPeerAlias := make(map[lnwire.ShortChannelID]string)
3✔
7994

3✔
7995
        // Helper function to extract a peer's node alias given its SCID.
3✔
7996
        getRemoteAlias := func(chanID lnwire.ShortChannelID) (string, error) {
6✔
7997
                // If we'd previously seen this chanID then return the cached
3✔
7998
                // peer alias.
3✔
7999
                if peerAlias, ok := chanToPeerAlias[chanID]; ok {
6✔
8000
                        return peerAlias, nil
3✔
8001
                }
3✔
8002

8003
                // Else call the server to look up the peer alias.
8004
                edge, err := r.GetChanInfo(ctx, &lnrpc.ChanInfoRequest{
3✔
8005
                        ChanId: chanID.ToUint64(),
3✔
8006
                })
3✔
8007
                if err != nil {
3✔
8008
                        return "", err
×
8009
                }
×
8010

8011
                remotePub := edge.Node1Pub
3✔
8012
                if r.selfNode.String() == edge.Node1Pub {
5✔
8013
                        remotePub = edge.Node2Pub
2✔
8014
                }
2✔
8015

8016
                vertex, err := route.NewVertexFromStr(remotePub)
3✔
8017
                if err != nil {
3✔
8018
                        return "", err
×
8019
                }
×
8020

8021
                peer, err := r.server.graphDB.FetchLightningNode(vertex)
3✔
8022
                if err != nil {
3✔
8023
                        return "", err
×
8024
                }
×
8025

8026
                // Cache the peer alias.
8027
                chanToPeerAlias[chanID] = peer.Alias
3✔
8028

3✔
8029
                return peer.Alias, nil
3✔
8030
        }
8031

8032
        // TODO(roasbeef): add settlement latency?
8033
        //  * use FPE on all records?
8034

8035
        // With the events retrieved, we'll now map them into the proper proto
8036
        // response.
8037
        //
8038
        // TODO(roasbeef): show in ns for the outside?
8039
        fwdingEvents := make(
3✔
8040
                []*lnrpc.ForwardingEvent, len(timeSlice.ForwardingEvents),
3✔
8041
        )
3✔
8042
        resp := &lnrpc.ForwardingHistoryResponse{
3✔
8043
                ForwardingEvents: fwdingEvents,
3✔
8044
                LastOffsetIndex:  timeSlice.LastIndexOffset,
3✔
8045
        }
3✔
8046
        for i, event := range timeSlice.ForwardingEvents {
6✔
8047
                amtInMsat := event.AmtIn
3✔
8048
                amtOutMsat := event.AmtOut
3✔
8049
                feeMsat := event.AmtIn - event.AmtOut
3✔
8050

3✔
8051
                resp.ForwardingEvents[i] = &lnrpc.ForwardingEvent{
3✔
8052
                        Timestamp:   uint64(event.Timestamp.Unix()),
3✔
8053
                        TimestampNs: uint64(event.Timestamp.UnixNano()),
3✔
8054
                        ChanIdIn:    event.IncomingChanID.ToUint64(),
3✔
8055
                        ChanIdOut:   event.OutgoingChanID.ToUint64(),
3✔
8056
                        AmtIn:       uint64(amtInMsat.ToSatoshis()),
3✔
8057
                        AmtOut:      uint64(amtOutMsat.ToSatoshis()),
3✔
8058
                        Fee:         uint64(feeMsat.ToSatoshis()),
3✔
8059
                        FeeMsat:     uint64(feeMsat),
3✔
8060
                        AmtInMsat:   uint64(amtInMsat),
3✔
8061
                        AmtOutMsat:  uint64(amtOutMsat),
3✔
8062
                }
3✔
8063

3✔
8064
                if req.PeerAliasLookup {
6✔
8065
                        aliasIn, err := getRemoteAlias(event.IncomingChanID)
3✔
8066
                        if err != nil {
3✔
8067
                                aliasIn = fmt.Sprintf("unable to lookup peer "+
×
8068
                                        "alias: %v", err)
×
8069
                        }
×
8070
                        aliasOut, err := getRemoteAlias(event.OutgoingChanID)
3✔
8071
                        if err != nil {
3✔
8072
                                aliasOut = fmt.Sprintf("unable to lookup peer"+
×
8073
                                        "alias: %v", err)
×
8074
                        }
×
8075
                        resp.ForwardingEvents[i].PeerAliasIn = aliasIn
3✔
8076
                        resp.ForwardingEvents[i].PeerAliasOut = aliasOut
3✔
8077
                }
8078
        }
8079

8080
        return resp, nil
3✔
8081
}
8082

8083
// ExportChannelBackup attempts to return an encrypted static channel backup
8084
// for the target channel identified by it channel point. The backup is
8085
// encrypted with a key generated from the aezeed seed of the user. The
8086
// returned backup can either be restored using the RestoreChannelBackup method
8087
// once lnd is running, or via the InitWallet and UnlockWallet methods from the
8088
// WalletUnlocker service.
8089
func (r *rpcServer) ExportChannelBackup(ctx context.Context,
8090
        in *lnrpc.ExportChannelBackupRequest) (*lnrpc.ChannelBackup, error) {
3✔
8091

3✔
8092
        // First, we'll convert the lnrpc channel point into a wire.OutPoint
3✔
8093
        // that we can manipulate.
3✔
8094
        txid, err := lnrpc.GetChanPointFundingTxid(in.ChanPoint)
3✔
8095
        if err != nil {
3✔
8096
                return nil, err
×
8097
        }
×
8098
        chanPoint := wire.OutPoint{
3✔
8099
                Hash:  *txid,
3✔
8100
                Index: in.ChanPoint.OutputIndex,
3✔
8101
        }
3✔
8102

3✔
8103
        // Next, we'll attempt to fetch a channel backup for this channel from
3✔
8104
        // the database. If this channel has been closed, or the outpoint is
3✔
8105
        // unknown, then we'll return an error
3✔
8106
        unpackedBackup, err := chanbackup.FetchBackupForChan(
3✔
8107
                chanPoint, r.server.chanStateDB, r.server.addrSource,
3✔
8108
        )
3✔
8109
        if err != nil {
3✔
8110
                return nil, err
×
8111
        }
×
8112

8113
        // At this point, we have an unpacked backup (plaintext) so we'll now
8114
        // attempt to serialize and encrypt it in order to create a packed
8115
        // backup.
8116
        packedBackups, err := chanbackup.PackStaticChanBackups(
3✔
8117
                []chanbackup.Single{*unpackedBackup},
3✔
8118
                r.server.cc.KeyRing,
3✔
8119
        )
3✔
8120
        if err != nil {
3✔
8121
                return nil, fmt.Errorf("packing of back ups failed: %w", err)
×
8122
        }
×
8123

8124
        // Before we proceed, we'll ensure that we received a backup for this
8125
        // channel, otherwise, we'll bail out.
8126
        packedBackup, ok := packedBackups[chanPoint]
3✔
8127
        if !ok {
3✔
8128
                return nil, fmt.Errorf("expected single backup for "+
×
8129
                        "ChannelPoint(%v), got %v", chanPoint,
×
8130
                        len(packedBackup))
×
8131
        }
×
8132

8133
        return &lnrpc.ChannelBackup{
3✔
8134
                ChanPoint:  in.ChanPoint,
3✔
8135
                ChanBackup: packedBackup,
3✔
8136
        }, nil
3✔
8137
}
8138

8139
// VerifyChanBackup allows a caller to verify the integrity of a channel backup
8140
// snapshot. This method will accept both either a packed Single or a packed
8141
// Multi. Specifying both will result in an error.
8142
func (r *rpcServer) VerifyChanBackup(ctx context.Context,
8143
        in *lnrpc.ChanBackupSnapshot) (*lnrpc.VerifyChanBackupResponse, error) {
3✔
8144

3✔
8145
        var (
3✔
8146
                channels []chanbackup.Single
3✔
8147
                err      error
3✔
8148
        )
3✔
8149
        switch {
3✔
8150
        // If neither a Single or Multi has been specified, then we have nothing
8151
        // to verify.
8152
        case in.GetSingleChanBackups() == nil && in.GetMultiChanBackup() == nil:
×
8153
                return nil, errors.New("either a Single or Multi channel " +
×
8154
                        "backup must be specified")
×
8155

8156
        // Either a Single or a Multi must be specified, but not both.
8157
        case in.GetSingleChanBackups() != nil && in.GetMultiChanBackup() != nil:
×
8158
                return nil, errors.New("either a Single or Multi channel " +
×
8159
                        "backup must be specified, but not both")
×
8160

8161
        // If a Single is specified then we'll only accept one of them to allow
8162
        // the caller to map the valid/invalid state for each individual Single.
8163
        case in.GetSingleChanBackups() != nil:
×
8164
                chanBackupsProtos := in.GetSingleChanBackups().ChanBackups
×
8165
                if len(chanBackupsProtos) != 1 {
×
8166
                        return nil, errors.New("only one Single is accepted " +
×
8167
                                "at a time")
×
8168
                }
×
8169

8170
                // First, we'll convert the raw byte slice into a type we can
8171
                // work with a bit better.
8172
                chanBackup := chanbackup.PackedSingles(
×
8173
                        [][]byte{chanBackupsProtos[0].ChanBackup},
×
8174
                )
×
8175

×
8176
                // With our PackedSingles created, we'll attempt to unpack the
×
8177
                // backup. If this fails, then we know the backup is invalid for
×
8178
                // some reason.
×
8179
                channels, err = chanBackup.Unpack(r.server.cc.KeyRing)
×
8180
                if err != nil {
×
8181
                        return nil, fmt.Errorf("invalid single channel "+
×
8182
                                "backup: %v", err)
×
8183
                }
×
8184

8185
        case in.GetMultiChanBackup() != nil:
3✔
8186
                // We'll convert the raw byte slice into a PackedMulti that we
3✔
8187
                // can easily work with.
3✔
8188
                packedMultiBackup := in.GetMultiChanBackup().MultiChanBackup
3✔
8189
                packedMulti := chanbackup.PackedMulti(packedMultiBackup)
3✔
8190

3✔
8191
                // We'll now attempt to unpack the Multi. If this fails, then we
3✔
8192
                // know it's invalid.
3✔
8193
                multi, err := packedMulti.Unpack(r.server.cc.KeyRing)
3✔
8194
                if err != nil {
3✔
8195
                        return nil, fmt.Errorf("invalid multi channel backup: "+
×
8196
                                "%v", err)
×
8197
                }
×
8198

8199
                channels = multi.StaticBackups
3✔
8200
        }
8201

8202
        return &lnrpc.VerifyChanBackupResponse{
3✔
8203
                ChanPoints: fn.Map(channels, func(c chanbackup.Single) string {
6✔
8204
                        return c.FundingOutpoint.String()
3✔
8205
                }),
3✔
8206
        }, nil
8207
}
8208

8209
// createBackupSnapshot converts the passed Single backup into a snapshot which
8210
// contains individual packed single backups, as well as a single packed multi
8211
// backup.
8212
func (r *rpcServer) createBackupSnapshot(backups []chanbackup.Single) (
8213
        *lnrpc.ChanBackupSnapshot, error) {
3✔
8214

3✔
8215
        // Once we have the set of back ups, we'll attempt to pack them all
3✔
8216
        // into a series of single channel backups.
3✔
8217
        singleChanPackedBackups, err := chanbackup.PackStaticChanBackups(
3✔
8218
                backups, r.server.cc.KeyRing,
3✔
8219
        )
3✔
8220
        if err != nil {
3✔
8221
                return nil, fmt.Errorf("unable to pack set of chan "+
×
8222
                        "backups: %v", err)
×
8223
        }
×
8224

8225
        // Now that we have our set of single packed backups, we'll morph that
8226
        // into a form that the proto response requires.
8227
        numBackups := len(singleChanPackedBackups)
3✔
8228
        singleBackupResp := &lnrpc.ChannelBackups{
3✔
8229
                ChanBackups: make([]*lnrpc.ChannelBackup, 0, numBackups),
3✔
8230
        }
3✔
8231
        for chanPoint, singlePackedBackup := range singleChanPackedBackups {
6✔
8232
                txid := chanPoint.Hash
3✔
8233
                rpcChanPoint := &lnrpc.ChannelPoint{
3✔
8234
                        FundingTxid: &lnrpc.ChannelPoint_FundingTxidBytes{
3✔
8235
                                FundingTxidBytes: txid[:],
3✔
8236
                        },
3✔
8237
                        OutputIndex: chanPoint.Index,
3✔
8238
                }
3✔
8239

3✔
8240
                singleBackupResp.ChanBackups = append(
3✔
8241
                        singleBackupResp.ChanBackups,
3✔
8242
                        &lnrpc.ChannelBackup{
3✔
8243
                                ChanPoint:  rpcChanPoint,
3✔
8244
                                ChanBackup: singlePackedBackup,
3✔
8245
                        },
3✔
8246
                )
3✔
8247
        }
3✔
8248

8249
        // In addition, to the set of single chan backups, we'll also create a
8250
        // single multi-channel backup which can be serialized into a single
8251
        // file for safe storage.
8252
        var b bytes.Buffer
3✔
8253
        unpackedMultiBackup := chanbackup.Multi{
3✔
8254
                StaticBackups: backups,
3✔
8255
        }
3✔
8256
        err = unpackedMultiBackup.PackToWriter(&b, r.server.cc.KeyRing)
3✔
8257
        if err != nil {
3✔
8258
                return nil, fmt.Errorf("unable to multi-pack backups: %w", err)
×
8259
        }
×
8260

8261
        multiBackupResp := &lnrpc.MultiChanBackup{
3✔
8262
                MultiChanBackup: b.Bytes(),
3✔
8263
        }
3✔
8264
        for _, singleBackup := range singleBackupResp.ChanBackups {
6✔
8265
                multiBackupResp.ChanPoints = append(
3✔
8266
                        multiBackupResp.ChanPoints, singleBackup.ChanPoint,
3✔
8267
                )
3✔
8268
        }
3✔
8269

8270
        return &lnrpc.ChanBackupSnapshot{
3✔
8271
                SingleChanBackups: singleBackupResp,
3✔
8272
                MultiChanBackup:   multiBackupResp,
3✔
8273
        }, nil
3✔
8274
}
8275

8276
// ExportAllChannelBackups returns static channel backups for all existing
8277
// channels known to lnd. A set of regular singular static channel backups for
8278
// each channel are returned. Additionally, a multi-channel backup is returned
8279
// as well, which contains a single encrypted blob containing the backups of
8280
// each channel.
8281
func (r *rpcServer) ExportAllChannelBackups(ctx context.Context,
8282
        in *lnrpc.ChanBackupExportRequest) (*lnrpc.ChanBackupSnapshot, error) {
3✔
8283

3✔
8284
        // First, we'll attempt to read back ups for ALL currently opened
3✔
8285
        // channels from disk.
3✔
8286
        allUnpackedBackups, err := chanbackup.FetchStaticChanBackups(
3✔
8287
                r.server.chanStateDB, r.server.addrSource,
3✔
8288
        )
3✔
8289
        if err != nil {
3✔
8290
                return nil, fmt.Errorf("unable to fetch all static chan "+
×
8291
                        "backups: %v", err)
×
8292
        }
×
8293

8294
        // With the backups assembled, we'll create a full snapshot.
8295
        return r.createBackupSnapshot(allUnpackedBackups)
3✔
8296
}
8297

8298
// RestoreChannelBackups accepts a set of singular channel backups, or a single
8299
// encrypted multi-chan backup and attempts to recover any funds remaining
8300
// within the channel. If we're able to unpack the backup, then the new channel
8301
// will be shown under listchannels, as well as pending channels.
8302
func (r *rpcServer) RestoreChannelBackups(ctx context.Context,
8303
        in *lnrpc.RestoreChanBackupRequest) (*lnrpc.RestoreBackupResponse, error) {
3✔
8304

3✔
8305
        // The server hasn't yet started, so it won't be able to service any of
3✔
8306
        // our requests, so we'll bail early here.
3✔
8307
        if !r.server.Started() {
3✔
8308
                return nil, ErrServerNotActive
×
8309
        }
×
8310

8311
        // First, we'll make our implementation of the
8312
        // chanbackup.ChannelRestorer interface which we'll use to properly
8313
        // restore either a set of chanbackup.Single or chanbackup.Multi
8314
        // backups.
8315
        chanRestorer := &chanDBRestorer{
3✔
8316
                db:         r.server.chanStateDB,
3✔
8317
                secretKeys: r.server.cc.KeyRing,
3✔
8318
                chainArb:   r.server.chainArb,
3✔
8319
        }
3✔
8320

3✔
8321
        // We'll accept either a list of Single backups, or a single Multi
3✔
8322
        // backup which contains several single backups.
3✔
8323
        var (
3✔
8324
                numRestored int
3✔
8325
                err         error
3✔
8326
        )
3✔
8327
        switch {
3✔
8328
        case in.GetChanBackups() != nil:
×
8329
                chanBackupsProtos := in.GetChanBackups()
×
8330

×
8331
                // Now that we know what type of backup we're working with,
×
8332
                // we'll parse them all out into a more suitable format.
×
8333
                packedBackups := make([][]byte, 0, len(chanBackupsProtos.ChanBackups))
×
8334
                for _, chanBackup := range chanBackupsProtos.ChanBackups {
×
8335
                        packedBackups = append(
×
8336
                                packedBackups, chanBackup.ChanBackup,
×
8337
                        )
×
8338
                }
×
8339

8340
                // With our backups obtained, we'll now restore them which will
8341
                // write the new backups to disk, and then attempt to connect
8342
                // out to any peers that we know of which were our prior
8343
                // channel peers.
8344
                numRestored, err = chanbackup.UnpackAndRecoverSingles(
×
8345
                        chanbackup.PackedSingles(packedBackups),
×
8346
                        r.server.cc.KeyRing, chanRestorer, r.server,
×
8347
                )
×
8348
                if err != nil {
×
8349
                        return nil, fmt.Errorf("unable to unpack single "+
×
8350
                                "backups: %v", err)
×
8351
                }
×
8352

8353
        case in.GetMultiChanBackup() != nil:
3✔
8354
                packedMultiBackup := in.GetMultiChanBackup()
3✔
8355

3✔
8356
                // With our backups obtained, we'll now restore them which will
3✔
8357
                // write the new backups to disk, and then attempt to connect
3✔
8358
                // out to any peers that we know of which were our prior
3✔
8359
                // channel peers.
3✔
8360
                packedMulti := chanbackup.PackedMulti(packedMultiBackup)
3✔
8361
                numRestored, err = chanbackup.UnpackAndRecoverMulti(
3✔
8362
                        packedMulti, r.server.cc.KeyRing, chanRestorer,
3✔
8363
                        r.server,
3✔
8364
                )
3✔
8365
                if err != nil {
3✔
8366
                        return nil, fmt.Errorf("unable to unpack chan "+
×
8367
                                "backup: %v", err)
×
8368
                }
×
8369
        }
8370

8371
        return &lnrpc.RestoreBackupResponse{
3✔
8372
                NumRestored: uint32(numRestored),
3✔
8373
        }, nil
3✔
8374
}
8375

8376
// SubscribeChannelBackups allows a client to sub-subscribe to the most up to
8377
// date information concerning the state of all channel back ups. Each time a
8378
// new channel is added, we return the new set of channels, along with a
8379
// multi-chan backup containing the backup info for all channels. Each time a
8380
// channel is closed, we send a new update, which contains new new chan back
8381
// ups, but the updated set of encrypted multi-chan backups with the closed
8382
// channel(s) removed.
8383
func (r *rpcServer) SubscribeChannelBackups(req *lnrpc.ChannelBackupSubscription,
8384
        updateStream lnrpc.Lightning_SubscribeChannelBackupsServer) error {
3✔
8385

3✔
8386
        // First, we'll subscribe to the primary channel notifier so we can
3✔
8387
        // obtain events for new pending/opened/closed channels.
3✔
8388
        chanSubscription, err := r.server.channelNotifier.SubscribeChannelEvents()
3✔
8389
        if err != nil {
3✔
8390
                return err
×
8391
        }
×
8392

8393
        defer chanSubscription.Cancel()
3✔
8394
        for {
6✔
8395
                select {
3✔
8396
                // A new event has been sent by the channel notifier, we'll
8397
                // assemble, then sling out a new event to the client.
8398
                case e := <-chanSubscription.Updates():
3✔
8399
                        // TODO(roasbeef): batch dispatch ntnfs
3✔
8400

3✔
8401
                        switch e.(type) {
3✔
8402

8403
                        // We only care about new/closed channels, so we'll
8404
                        // skip any events for active/inactive channels.
8405
                        // To make the subscription behave the same way as the
8406
                        // synchronous call and the file based backup, we also
8407
                        // include pending channels in the update.
8408
                        case channelnotifier.ActiveChannelEvent:
3✔
8409
                                continue
3✔
8410
                        case channelnotifier.InactiveChannelEvent:
3✔
8411
                                continue
3✔
8412
                        case channelnotifier.ActiveLinkEvent:
3✔
8413
                                continue
3✔
8414
                        case channelnotifier.InactiveLinkEvent:
3✔
8415
                                continue
3✔
8416
                        }
8417

8418
                        // Now that we know the channel state has changed,
8419
                        // we'll obtains the current set of single channel
8420
                        // backups from disk.
8421
                        chanBackups, err := chanbackup.FetchStaticChanBackups(
3✔
8422
                                r.server.chanStateDB, r.server.addrSource,
3✔
8423
                        )
3✔
8424
                        if err != nil {
3✔
8425
                                return fmt.Errorf("unable to fetch all "+
×
8426
                                        "static chan backups: %v", err)
×
8427
                        }
×
8428

8429
                        // With our backups obtained, we'll pack them into a
8430
                        // snapshot and send them back to the client.
8431
                        backupSnapshot, err := r.createBackupSnapshot(
3✔
8432
                                chanBackups,
3✔
8433
                        )
3✔
8434
                        if err != nil {
3✔
8435
                                return err
×
8436
                        }
×
8437
                        err = updateStream.Send(backupSnapshot)
3✔
8438
                        if err != nil {
3✔
8439
                                return err
×
8440
                        }
×
8441

8442
                // The response stream's context for whatever reason has been
8443
                // closed. If context is closed by an exceeded deadline we will
8444
                // return an error.
8445
                case <-updateStream.Context().Done():
3✔
8446
                        if errors.Is(updateStream.Context().Err(), context.Canceled) {
6✔
8447
                                return nil
3✔
8448
                        }
3✔
8449
                        return updateStream.Context().Err()
×
8450

8451
                case <-r.quit:
×
8452
                        return nil
×
8453
                }
8454
        }
8455
}
8456

8457
// ChannelAcceptor dispatches a bi-directional streaming RPC in which
8458
// OpenChannel requests are sent to the client and the client responds with
8459
// a boolean that tells LND whether or not to accept the channel. This allows
8460
// node operators to specify their own criteria for accepting inbound channels
8461
// through a single persistent connection.
8462
func (r *rpcServer) ChannelAcceptor(stream lnrpc.Lightning_ChannelAcceptorServer) error {
3✔
8463
        chainedAcceptor := r.chanPredicate
3✔
8464

3✔
8465
        // Create a new RPCAcceptor which will send requests into the
3✔
8466
        // newRequests channel when it receives them.
3✔
8467
        rpcAcceptor := chanacceptor.NewRPCAcceptor(
3✔
8468
                stream.Recv, stream.Send, r.cfg.AcceptorTimeout,
3✔
8469
                r.cfg.ActiveNetParams.Params, r.quit,
3✔
8470
        )
3✔
8471

3✔
8472
        // Add the RPCAcceptor to the ChainedAcceptor and defer its removal.
3✔
8473
        id := chainedAcceptor.AddAcceptor(rpcAcceptor)
3✔
8474
        defer chainedAcceptor.RemoveAcceptor(id)
3✔
8475

3✔
8476
        // Run the rpc acceptor, which will accept requests for channel
3✔
8477
        // acceptance decisions from our chained acceptor, send them to the
3✔
8478
        // channel acceptor and listen for and report responses. This function
3✔
8479
        // blocks, and will exit if the rpcserver receives the instruction to
3✔
8480
        // shutdown, or the client cancels.
3✔
8481
        return rpcAcceptor.Run()
3✔
8482
}
3✔
8483

8484
// BakeMacaroon allows the creation of a new macaroon with custom read and write
8485
// permissions. No first-party caveats are added since this can be done offline.
8486
// If the --allow-external-permissions flag is set, the RPC will allow
8487
// external permissions that LND is not aware of.
8488
func (r *rpcServer) BakeMacaroon(ctx context.Context,
8489
        req *lnrpc.BakeMacaroonRequest) (*lnrpc.BakeMacaroonResponse, error) {
3✔
8490

3✔
8491
        // If the --no-macaroons flag is used to start lnd, the macaroon service
3✔
8492
        // is not initialized. Therefore we can't bake new macaroons.
3✔
8493
        if r.macService == nil {
3✔
8494
                return nil, errMacaroonDisabled
×
8495
        }
×
8496

8497
        helpMsg := fmt.Sprintf("supported actions are %v, supported entities "+
3✔
8498
                "are %v", validActions, validEntities)
3✔
8499

3✔
8500
        // Don't allow empty permission list as it doesn't make sense to have
3✔
8501
        // a macaroon that is not allowed to access any RPC.
3✔
8502
        if len(req.Permissions) == 0 {
6✔
8503
                return nil, fmt.Errorf("permission list cannot be empty. "+
3✔
8504
                        "specify at least one action/entity pair. %s", helpMsg)
3✔
8505
        }
3✔
8506

8507
        // Validate and map permission struct used by gRPC to the one used by
8508
        // the bakery. If the --allow-external-permissions flag is set, we
8509
        // will not validate, but map.
8510
        requestedPermissions := make([]bakery.Op, len(req.Permissions))
3✔
8511
        for idx, op := range req.Permissions {
6✔
8512
                if req.AllowExternalPermissions {
6✔
8513
                        requestedPermissions[idx] = bakery.Op{
3✔
8514
                                Entity: op.Entity,
3✔
8515
                                Action: op.Action,
3✔
8516
                        }
3✔
8517
                        continue
3✔
8518
                }
8519

8520
                if !stringInSlice(op.Entity, validEntities) {
6✔
8521
                        return nil, fmt.Errorf("invalid permission entity. %s",
3✔
8522
                                helpMsg)
3✔
8523
                }
3✔
8524

8525
                // Either we have the special entity "uri" which specifies a
8526
                // full gRPC URI or we have one of the pre-defined actions.
8527
                if op.Entity == macaroons.PermissionEntityCustomURI {
6✔
8528
                        allPermissions := r.interceptorChain.Permissions()
3✔
8529
                        _, ok := allPermissions[op.Action]
3✔
8530
                        if !ok {
3✔
8531
                                return nil, fmt.Errorf("invalid permission " +
×
8532
                                        "action, must be an existing URI in " +
×
8533
                                        "the format /package.Service/" +
×
8534
                                        "MethodName")
×
8535
                        }
×
8536
                } else if !stringInSlice(op.Action, validActions) {
6✔
8537
                        return nil, fmt.Errorf("invalid permission action. %s",
3✔
8538
                                helpMsg)
3✔
8539
                }
3✔
8540

8541
                requestedPermissions[idx] = bakery.Op{
3✔
8542
                        Entity: op.Entity,
3✔
8543
                        Action: op.Action,
3✔
8544
                }
3✔
8545
        }
8546

8547
        // Convert root key id from uint64 to bytes. Because the
8548
        // DefaultRootKeyID is a digit 0 expressed in a byte slice of a string
8549
        // "0", we will keep the IDs in the same format - all must be numeric,
8550
        // and must be a byte slice of string value of the digit, e.g.,
8551
        // uint64(123) to string(123).
8552
        rootKeyID := []byte(strconv.FormatUint(req.RootKeyId, 10))
3✔
8553

3✔
8554
        // Bake new macaroon with the given permissions and send it binary
3✔
8555
        // serialized and hex encoded to the client.
3✔
8556
        newMac, err := r.macService.NewMacaroon(
3✔
8557
                ctx, rootKeyID, requestedPermissions...,
3✔
8558
        )
3✔
8559
        if err != nil {
3✔
8560
                return nil, err
×
8561
        }
×
8562
        newMacBytes, err := newMac.M().MarshalBinary()
3✔
8563
        if err != nil {
3✔
8564
                return nil, err
×
8565
        }
×
8566
        resp := &lnrpc.BakeMacaroonResponse{}
3✔
8567
        resp.Macaroon = hex.EncodeToString(newMacBytes)
3✔
8568

3✔
8569
        return resp, nil
3✔
8570
}
8571

8572
// ListMacaroonIDs returns a list of macaroon root key IDs in use.
8573
func (r *rpcServer) ListMacaroonIDs(ctx context.Context,
8574
        req *lnrpc.ListMacaroonIDsRequest) (
8575
        *lnrpc.ListMacaroonIDsResponse, error) {
3✔
8576

3✔
8577
        // If the --no-macaroons flag is used to start lnd, the macaroon service
3✔
8578
        // is not initialized. Therefore we can't show any IDs.
3✔
8579
        if r.macService == nil {
3✔
8580
                return nil, errMacaroonDisabled
×
8581
        }
×
8582

8583
        rootKeyIDByteSlice, err := r.macService.ListMacaroonIDs(ctx)
3✔
8584
        if err != nil {
3✔
8585
                return nil, err
×
8586
        }
×
8587

8588
        var rootKeyIDs []uint64
3✔
8589
        for _, value := range rootKeyIDByteSlice {
6✔
8590
                // Convert bytes into uint64.
3✔
8591
                id, err := strconv.ParseUint(string(value), 10, 64)
3✔
8592
                if err != nil {
3✔
8593
                        return nil, err
×
8594
                }
×
8595

8596
                rootKeyIDs = append(rootKeyIDs, id)
3✔
8597
        }
8598

8599
        return &lnrpc.ListMacaroonIDsResponse{RootKeyIds: rootKeyIDs}, nil
3✔
8600
}
8601

8602
// DeleteMacaroonID removes a specific macaroon ID.
8603
func (r *rpcServer) DeleteMacaroonID(ctx context.Context,
8604
        req *lnrpc.DeleteMacaroonIDRequest) (
8605
        *lnrpc.DeleteMacaroonIDResponse, error) {
3✔
8606

3✔
8607
        // If the --no-macaroons flag is used to start lnd, the macaroon service
3✔
8608
        // is not initialized. Therefore we can't delete any IDs.
3✔
8609
        if r.macService == nil {
3✔
8610
                return nil, errMacaroonDisabled
×
8611
        }
×
8612

8613
        // Convert root key id from uint64 to bytes. Because the
8614
        // DefaultRootKeyID is a digit 0 expressed in a byte slice of a string
8615
        // "0", we will keep the IDs in the same format - all must be digit, and
8616
        // must be a byte slice of string value of the digit.
8617
        rootKeyID := []byte(strconv.FormatUint(req.RootKeyId, 10))
3✔
8618
        deletedIDBytes, err := r.macService.DeleteMacaroonID(ctx, rootKeyID)
3✔
8619
        if err != nil {
6✔
8620
                return nil, err
3✔
8621
        }
3✔
8622

8623
        return &lnrpc.DeleteMacaroonIDResponse{
3✔
8624
                // If the root key ID doesn't exist, it won't be deleted. We
3✔
8625
                // will return a response with deleted = false, otherwise true.
3✔
8626
                Deleted: deletedIDBytes != nil,
3✔
8627
        }, nil
3✔
8628
}
8629

8630
// ListPermissions lists all RPC method URIs and their required macaroon
8631
// permissions to access them.
8632
func (r *rpcServer) ListPermissions(_ context.Context,
8633
        _ *lnrpc.ListPermissionsRequest) (*lnrpc.ListPermissionsResponse,
8634
        error) {
3✔
8635

3✔
8636
        permissionMap := make(map[string]*lnrpc.MacaroonPermissionList)
3✔
8637
        for uri, perms := range r.interceptorChain.Permissions() {
6✔
8638
                rpcPerms := make([]*lnrpc.MacaroonPermission, len(perms))
3✔
8639
                for idx, perm := range perms {
6✔
8640
                        rpcPerms[idx] = &lnrpc.MacaroonPermission{
3✔
8641
                                Entity: perm.Entity,
3✔
8642
                                Action: perm.Action,
3✔
8643
                        }
3✔
8644
                }
3✔
8645
                permissionMap[uri] = &lnrpc.MacaroonPermissionList{
3✔
8646
                        Permissions: rpcPerms,
3✔
8647
                }
3✔
8648
        }
8649

8650
        return &lnrpc.ListPermissionsResponse{
3✔
8651
                MethodPermissions: permissionMap,
3✔
8652
        }, nil
3✔
8653
}
8654

8655
// CheckMacaroonPermissions checks the caveats and permissions of a macaroon.
8656
func (r *rpcServer) CheckMacaroonPermissions(ctx context.Context,
8657
        req *lnrpc.CheckMacPermRequest) (*lnrpc.CheckMacPermResponse, error) {
3✔
8658

3✔
8659
        // Turn grpc macaroon permission into bakery.Op for the server to
3✔
8660
        // process.
3✔
8661
        permissions := make([]bakery.Op, len(req.Permissions))
3✔
8662
        for idx, perm := range req.Permissions {
6✔
8663
                permissions[idx] = bakery.Op{
3✔
8664
                        Entity: perm.Entity,
3✔
8665
                        Action: perm.Action,
3✔
8666
                }
3✔
8667
        }
3✔
8668

8669
        err := r.macService.CheckMacAuth(
3✔
8670
                ctx, req.Macaroon, permissions, req.FullMethod,
3✔
8671
        )
3✔
8672
        if err != nil {
6✔
8673
                return nil, status.Error(codes.InvalidArgument, err.Error())
3✔
8674
        }
3✔
8675

8676
        return &lnrpc.CheckMacPermResponse{
3✔
8677
                Valid: true,
3✔
8678
        }, nil
3✔
8679
}
8680

8681
// FundingStateStep is an advanced funding related call that allows the caller
8682
// to either execute some preparatory steps for a funding workflow, or manually
8683
// progress a funding workflow. The primary way a funding flow is identified is
8684
// via its pending channel ID. As an example, this method can be used to
8685
// specify that we're expecting a funding flow for a particular pending channel
8686
// ID, for which we need to use specific parameters.  Alternatively, this can
8687
// be used to interactively drive PSBT signing for funding for partially
8688
// complete funding transactions.
8689
func (r *rpcServer) FundingStateStep(ctx context.Context,
8690
        in *lnrpc.FundingTransitionMsg) (*lnrpc.FundingStateStepResp, error) {
3✔
8691

3✔
8692
        var pendingChanID [32]byte
3✔
8693
        switch {
3✔
8694
        // If this is a message to register a new shim that is an external
8695
        // channel point, then we'll contact the wallet to register this new
8696
        // shim. A user will use this method to register a new channel funding
8697
        // workflow which has already been partially negotiated outside of the
8698
        // core protocol.
8699
        case in.GetShimRegister() != nil &&
8700
                in.GetShimRegister().GetChanPointShim() != nil:
3✔
8701

3✔
8702
                rpcShimIntent := in.GetShimRegister().GetChanPointShim()
3✔
8703

3✔
8704
                // Using the rpc shim as a template, we'll construct a new
3✔
8705
                // chanfunding.Assembler that is able to express proper
3✔
8706
                // formulation of this expected channel.
3✔
8707
                shimAssembler, err := newFundingShimAssembler(
3✔
8708
                        rpcShimIntent, false, r.server.cc.KeyRing,
3✔
8709
                )
3✔
8710
                if err != nil {
3✔
8711
                        return nil, err
×
8712
                }
×
8713
                req := &chanfunding.Request{
3✔
8714
                        RemoteAmt: btcutil.Amount(rpcShimIntent.Amt),
3✔
8715
                }
3✔
8716
                shimIntent, err := shimAssembler.ProvisionChannel(req)
3✔
8717
                if err != nil {
3✔
8718
                        return nil, err
×
8719
                }
×
8720

8721
                // Once we have the intent, we'll register it with the wallet.
8722
                // Once we receive an incoming funding request that uses this
8723
                // pending channel ID, then this shim will be dispatched in
8724
                // place of our regular funding workflow.
8725
                copy(pendingChanID[:], rpcShimIntent.PendingChanId)
3✔
8726
                err = r.server.cc.Wallet.RegisterFundingIntent(
3✔
8727
                        pendingChanID, shimIntent,
3✔
8728
                )
3✔
8729
                if err != nil {
6✔
8730
                        return nil, err
3✔
8731
                }
3✔
8732

8733
        // There is no need to register a PSBT shim before opening the channel,
8734
        // even though our RPC message structure allows for it. Inform the user
8735
        // by returning a proper error instead of just doing nothing.
8736
        case in.GetShimRegister() != nil &&
8737
                in.GetShimRegister().GetPsbtShim() != nil:
×
8738

×
8739
                return nil, fmt.Errorf("PSBT shim must only be sent when " +
×
8740
                        "opening a channel")
×
8741

8742
        // If this is a transition to cancel an existing shim, then we'll pass
8743
        // this message along to the wallet, informing it that the intent no
8744
        // longer needs to be considered and should be cleaned up.
8745
        case in.GetShimCancel() != nil:
×
8746
                rpcsLog.Debugf("Canceling funding shim for pending_id=%x",
×
8747
                        in.GetShimCancel().PendingChanId)
×
8748

×
8749
                copy(pendingChanID[:], in.GetShimCancel().PendingChanId)
×
8750
                err := r.server.cc.Wallet.CancelFundingIntent(pendingChanID)
×
8751
                if err != nil {
×
8752
                        return nil, err
×
8753
                }
×
8754

8755
        // If this is a transition to verify the PSBT for an existing shim,
8756
        // we'll do so and then store the verified PSBT for later so we can
8757
        // compare it to the final, signed one.
8758
        case in.GetPsbtVerify() != nil:
3✔
8759
                rpcsLog.Debugf("Verifying PSBT for pending_id=%x",
3✔
8760
                        in.GetPsbtVerify().PendingChanId)
3✔
8761

3✔
8762
                copy(pendingChanID[:], in.GetPsbtVerify().PendingChanId)
3✔
8763
                packet, err := psbt.NewFromRawBytes(
3✔
8764
                        bytes.NewReader(in.GetPsbtVerify().FundedPsbt), false,
3✔
8765
                )
3✔
8766
                if err != nil {
3✔
8767
                        return nil, fmt.Errorf("error parsing psbt: %w", err)
×
8768
                }
×
8769

8770
                err = r.server.cc.Wallet.PsbtFundingVerify(
3✔
8771
                        pendingChanID, packet, in.GetPsbtVerify().SkipFinalize,
3✔
8772
                )
3✔
8773
                if err != nil {
3✔
8774
                        return nil, err
×
8775
                }
×
8776

8777
        // If this is a transition to finalize the PSBT funding flow, we compare
8778
        // the final PSBT to the previously verified one and if nothing
8779
        // unexpected was changed, continue the channel opening process.
8780
        case in.GetPsbtFinalize() != nil:
3✔
8781
                msg := in.GetPsbtFinalize()
3✔
8782
                rpcsLog.Debugf("Finalizing PSBT for pending_id=%x",
3✔
8783
                        msg.PendingChanId)
3✔
8784

3✔
8785
                copy(pendingChanID[:], in.GetPsbtFinalize().PendingChanId)
3✔
8786

3✔
8787
                var (
3✔
8788
                        packet *psbt.Packet
3✔
8789
                        rawTx  *wire.MsgTx
3✔
8790
                        err    error
3✔
8791
                )
3✔
8792

3✔
8793
                // Either the signed PSBT or the raw transaction need to be set
3✔
8794
                // but not both at the same time.
3✔
8795
                switch {
3✔
8796
                case len(msg.SignedPsbt) > 0 && len(msg.FinalRawTx) > 0:
×
8797
                        return nil, fmt.Errorf("cannot set both signed PSBT " +
×
8798
                                "and final raw TX at the same time")
×
8799

8800
                case len(msg.SignedPsbt) > 0:
3✔
8801
                        packet, err = psbt.NewFromRawBytes(
3✔
8802
                                bytes.NewReader(in.GetPsbtFinalize().SignedPsbt),
3✔
8803
                                false,
3✔
8804
                        )
3✔
8805
                        if err != nil {
3✔
8806
                                return nil, fmt.Errorf("error parsing psbt: %w",
×
8807
                                        err)
×
8808
                        }
×
8809

8810
                case len(msg.FinalRawTx) > 0:
3✔
8811
                        rawTx = &wire.MsgTx{}
3✔
8812
                        err = rawTx.Deserialize(bytes.NewReader(msg.FinalRawTx))
3✔
8813
                        if err != nil {
3✔
8814
                                return nil, fmt.Errorf("error parsing final "+
×
8815
                                        "raw TX: %v", err)
×
8816
                        }
×
8817

8818
                default:
×
8819
                        return nil, fmt.Errorf("PSBT or raw transaction to " +
×
8820
                                "finalize missing")
×
8821
                }
8822

8823
                err = r.server.cc.Wallet.PsbtFundingFinalize(
3✔
8824
                        pendingChanID, packet, rawTx,
3✔
8825
                )
3✔
8826
                if err != nil {
3✔
8827
                        return nil, err
×
8828
                }
×
8829
        }
8830

8831
        // TODO(roasbeef): extend PendingChannels to also show shims
8832

8833
        // TODO(roasbeef): return resulting state? also add a method to query
8834
        // current state?
8835
        return &lnrpc.FundingStateStepResp{}, nil
3✔
8836
}
8837

8838
// RegisterRPCMiddleware adds a new gRPC middleware to the interceptor chain. A
8839
// gRPC middleware is software component external to lnd that aims to add
8840
// additional business logic to lnd by observing/intercepting/validating
8841
// incoming gRPC client requests and (if needed) replacing/overwriting outgoing
8842
// messages before they're sent to the client. When registering the middleware
8843
// must identify itself and indicate what custom macaroon caveats it wants to
8844
// be responsible for. Only requests that contain a macaroon with that specific
8845
// custom caveat are then sent to the middleware for inspection. As a security
8846
// measure, _no_ middleware can intercept requests made with _unencumbered_
8847
// macaroons!
8848
func (r *rpcServer) RegisterRPCMiddleware(
8849
        stream lnrpc.Lightning_RegisterRPCMiddlewareServer) error {
3✔
8850

3✔
8851
        // This is a security critical functionality and needs to be enabled
3✔
8852
        // specifically by the user.
3✔
8853
        if !r.cfg.RPCMiddleware.Enable {
3✔
8854
                return fmt.Errorf("RPC middleware not enabled in config")
×
8855
        }
×
8856

8857
        // When registering a middleware the first message being sent from the
8858
        // middleware must be a registration message containing its name and the
8859
        // custom caveat it wants to register for.
8860
        var (
3✔
8861
                registerChan     = make(chan *lnrpc.MiddlewareRegistration, 1)
3✔
8862
                registerDoneChan = make(chan struct{})
3✔
8863
                errChan          = make(chan error, 1)
3✔
8864
        )
3✔
8865
        ctxc, cancel := context.WithTimeout(
3✔
8866
                stream.Context(), r.cfg.RPCMiddleware.InterceptTimeout,
3✔
8867
        )
3✔
8868
        defer cancel()
3✔
8869

3✔
8870
        // Read the first message in a goroutine because the Recv method blocks
3✔
8871
        // until the message arrives.
3✔
8872
        go func() {
6✔
8873
                msg, err := stream.Recv()
3✔
8874
                if err != nil {
3✔
8875
                        errChan <- err
×
8876

×
8877
                        return
×
8878
                }
×
8879

8880
                registerChan <- msg.GetRegister()
3✔
8881
        }()
8882

8883
        // Wait for the initial message to arrive or time out if it takes too
8884
        // long.
8885
        var registerMsg *lnrpc.MiddlewareRegistration
3✔
8886
        select {
3✔
8887
        case registerMsg = <-registerChan:
3✔
8888
                if registerMsg == nil {
3✔
8889
                        return fmt.Errorf("invalid initial middleware " +
×
8890
                                "registration message")
×
8891
                }
×
8892

8893
        case err := <-errChan:
×
8894
                return fmt.Errorf("error receiving initial middleware "+
×
8895
                        "registration message: %v", err)
×
8896

8897
        case <-ctxc.Done():
×
8898
                return ctxc.Err()
×
8899

8900
        case <-r.quit:
×
8901
                return ErrServerShuttingDown
×
8902
        }
8903

8904
        // Make sure the registration is valid.
8905
        const nameMinLength = 5
3✔
8906
        if len(registerMsg.MiddlewareName) < nameMinLength {
6✔
8907
                return fmt.Errorf("invalid middleware name, use descriptive "+
3✔
8908
                        "name of at least %d characters", nameMinLength)
3✔
8909
        }
3✔
8910

8911
        readOnly := registerMsg.ReadOnlyMode
3✔
8912
        caveatName := registerMsg.CustomMacaroonCaveatName
3✔
8913
        switch {
3✔
8914
        case readOnly && len(caveatName) > 0:
3✔
8915
                return fmt.Errorf("cannot set read-only and custom caveat " +
3✔
8916
                        "name at the same time")
3✔
8917

8918
        case !readOnly && len(caveatName) < nameMinLength:
3✔
8919
                return fmt.Errorf("need to set either custom caveat name "+
3✔
8920
                        "of at least %d characters or read-only mode",
3✔
8921
                        nameMinLength)
3✔
8922
        }
8923

8924
        middleware := rpcperms.NewMiddlewareHandler(
3✔
8925
                registerMsg.MiddlewareName,
3✔
8926
                caveatName, readOnly, stream.Recv, stream.Send,
3✔
8927
                r.cfg.RPCMiddleware.InterceptTimeout,
3✔
8928
                r.cfg.ActiveNetParams.Params, r.quit,
3✔
8929
        )
3✔
8930

3✔
8931
        // Add the RPC middleware to the interceptor chain and defer its
3✔
8932
        // removal.
3✔
8933
        if err := r.interceptorChain.RegisterMiddleware(middleware); err != nil {
3✔
8934
                return fmt.Errorf("error registering middleware: %w", err)
×
8935
        }
×
8936
        defer r.interceptorChain.RemoveMiddleware(registerMsg.MiddlewareName)
3✔
8937

3✔
8938
        // Send a message to the client to indicate that the registration has
3✔
8939
        // successfully completed.
3✔
8940
        regCompleteMsg := &lnrpc.RPCMiddlewareRequest{
3✔
8941
                InterceptType: &lnrpc.RPCMiddlewareRequest_RegComplete{
3✔
8942
                        RegComplete: true,
3✔
8943
                },
3✔
8944
        }
3✔
8945

3✔
8946
        // Send the message in a goroutine because the Send method blocks until
3✔
8947
        // the message is read by the client.
3✔
8948
        go func() {
6✔
8949
                err := stream.Send(regCompleteMsg)
3✔
8950
                if err != nil {
3✔
8951
                        errChan <- err
×
8952
                        return
×
8953
                }
×
8954

8955
                close(registerDoneChan)
3✔
8956
        }()
8957

8958
        select {
3✔
8959
        case err := <-errChan:
×
8960
                return fmt.Errorf("error sending middleware registration "+
×
8961
                        "complete message: %v", err)
×
8962

8963
        case <-ctxc.Done():
×
8964
                return ctxc.Err()
×
8965

8966
        case <-r.quit:
×
8967
                return ErrServerShuttingDown
×
8968

8969
        case <-registerDoneChan:
3✔
8970
        }
8971

8972
        return middleware.Run()
3✔
8973
}
8974

8975
// SendCustomMessage sends a custom peer message.
8976
func (r *rpcServer) SendCustomMessage(_ context.Context,
8977
        req *lnrpc.SendCustomMessageRequest) (*lnrpc.SendCustomMessageResponse,
8978
        error) {
3✔
8979

3✔
8980
        peer, err := route.NewVertexFromBytes(req.Peer)
3✔
8981
        if err != nil {
3✔
8982
                return nil, err
×
8983
        }
×
8984

8985
        err = r.server.SendCustomMessage(
3✔
8986
                peer, lnwire.MessageType(req.Type), req.Data,
3✔
8987
        )
3✔
8988
        switch {
3✔
8989
        case errors.Is(err, ErrPeerNotConnected):
×
8990
                return nil, status.Error(codes.NotFound, err.Error())
×
8991
        case err != nil:
3✔
8992
                return nil, err
3✔
8993
        }
8994

8995
        return &lnrpc.SendCustomMessageResponse{
3✔
8996
                Status: "message sent successfully",
3✔
8997
        }, nil
3✔
8998
}
8999

9000
// SubscribeCustomMessages subscribes to a stream of incoming custom peer
9001
// messages.
9002
func (r *rpcServer) SubscribeCustomMessages(
9003
        _ *lnrpc.SubscribeCustomMessagesRequest,
9004
        server lnrpc.Lightning_SubscribeCustomMessagesServer) error {
3✔
9005

3✔
9006
        client, err := r.server.SubscribeCustomMessages()
3✔
9007
        if err != nil {
3✔
9008
                return err
×
9009
        }
×
9010
        defer client.Cancel()
3✔
9011

3✔
9012
        for {
6✔
9013
                select {
3✔
9014
                case <-client.Quit():
×
9015
                        return errors.New("shutdown")
×
9016

9017
                case <-server.Context().Done():
3✔
9018
                        return server.Context().Err()
3✔
9019

9020
                case update := <-client.Updates():
3✔
9021
                        customMsg := update.(*CustomMessage)
3✔
9022

3✔
9023
                        err := server.Send(&lnrpc.CustomMessage{
3✔
9024
                                Peer: customMsg.Peer[:],
3✔
9025
                                Data: customMsg.Msg.Data,
3✔
9026
                                Type: uint32(customMsg.Msg.Type),
3✔
9027
                        })
3✔
9028
                        if err != nil {
3✔
9029
                                return err
×
9030
                        }
×
9031
                }
9032
        }
9033
}
9034

9035
// ListAliases returns the set of all aliases we have ever allocated along with
9036
// their base SCIDs and possibly a separate confirmed SCID in the case of
9037
// zero-conf.
9038
func (r *rpcServer) ListAliases(_ context.Context,
9039
        _ *lnrpc.ListAliasesRequest) (*lnrpc.ListAliasesResponse, error) {
×
9040

×
9041
        // Fetch the map of all aliases.
×
9042
        mapAliases := r.server.aliasMgr.ListAliases()
×
9043

×
9044
        // Fill out the response. This does not include the zero-conf confirmed
×
9045
        // SCID. Doing so would require more database lookups, and it can be
×
9046
        // cross-referenced with the output of ListChannels/ClosedChannels.
×
9047
        resp := &lnrpc.ListAliasesResponse{
×
9048
                AliasMaps: make([]*lnrpc.AliasMap, 0),
×
9049
        }
×
9050

×
9051
        // Now we need to parse the created mappings into an rpc response.
×
9052
        resp.AliasMaps = lnrpc.MarshalAliasMap(mapAliases)
×
9053

×
9054
        return resp, nil
×
9055
}
×
9056

9057
// rpcInitiator returns the correct lnrpc initiator for channels where we have
9058
// a record of the opening channel.
9059
func rpcInitiator(isInitiator bool) lnrpc.Initiator {
3✔
9060
        if isInitiator {
6✔
9061
                return lnrpc.Initiator_INITIATOR_LOCAL
3✔
9062
        }
3✔
9063

9064
        return lnrpc.Initiator_INITIATOR_REMOTE
3✔
9065
}
9066

9067
// chainSyncInfo wraps info about the best block and whether the system is
9068
// synced to that block.
9069
type chainSyncInfo struct {
9070
        // isSynced specifies whether the whole system is considered synced.
9071
        // When true, it means the following subsystems are at the best height
9072
        // reported by the chain backend,
9073
        // - wallet.
9074
        // - channel graph.
9075
        // - blockbeat dispatcher.
9076
        isSynced bool
9077

9078
        // bestHeight is the current height known to the chain backend.
9079
        bestHeight int32
9080

9081
        // blockHash is the hash of the current block known to the chain
9082
        // backend.
9083
        blockHash chainhash.Hash
9084

9085
        // timestamp is the block's timestamp the wallet has synced to.
9086
        timestamp int64
9087
}
9088

9089
// getChainSyncInfo queries the chain backend, the wallet, the channel router
9090
// and the blockbeat dispatcher to determine the best block and whether the
9091
// system is considered synced.
9092
func (r *rpcServer) getChainSyncInfo() (*chainSyncInfo, error) {
3✔
9093
        bestHash, bestHeight, err := r.server.cc.ChainIO.GetBestBlock()
3✔
9094
        if err != nil {
3✔
9095
                return nil, fmt.Errorf("unable to get best block info: %w", err)
×
9096
        }
×
9097

9098
        isSynced, bestHeaderTimestamp, err := r.server.cc.Wallet.IsSynced()
3✔
9099
        if err != nil {
3✔
9100
                return nil, fmt.Errorf("unable to sync PoV of the wallet "+
×
9101
                        "with current best block in the main chain: %v", err)
×
9102
        }
×
9103

9104
        // Create an info to be returned.
9105
        info := &chainSyncInfo{
3✔
9106
                isSynced:   isSynced,
3✔
9107
                bestHeight: bestHeight,
3✔
9108
                blockHash:  *bestHash,
3✔
9109
                timestamp:  bestHeaderTimestamp,
3✔
9110
        }
3✔
9111

3✔
9112
        // Exit early if the wallet is not synced.
3✔
9113
        if !isSynced {
4✔
9114
                rpcsLog.Debugf("Wallet is not synced to height %v yet",
1✔
9115
                        bestHeight)
1✔
9116

1✔
9117
                return info, nil
1✔
9118
        }
1✔
9119

9120
        // If the router does full channel validation, it has a lot of work to
9121
        // do for each block. So it might be possible that it isn't yet up to
9122
        // date with the most recent block, even if the wallet is. This can
9123
        // happen in environments with high CPU load (such as parallel itests).
9124
        // Since the `synced_to_chain` flag in the response of this call is used
9125
        // by many wallets (and also our itests) to make sure everything's up to
9126
        // date, we add the router's state to it. So the flag will only toggle
9127
        // to true once the router was also able to catch up.
9128
        if !r.cfg.Routing.AssumeChannelValid {
6✔
9129
                routerHeight := r.server.graphBuilder.SyncedHeight()
3✔
9130
                isSynced = uint32(bestHeight) == routerHeight
3✔
9131
        }
3✔
9132

9133
        // Exit early if the channel graph is not synced.
9134
        if !isSynced {
4✔
9135
                rpcsLog.Debugf("Graph is not synced to height %v yet",
1✔
9136
                        bestHeight)
1✔
9137

1✔
9138
                return info, nil
1✔
9139
        }
1✔
9140

9141
        // Given the wallet and the channel router are synced, we now check
9142
        // whether the blockbeat dispatcher is synced.
9143
        height := r.server.blockbeatDispatcher.CurrentHeight()
3✔
9144

3✔
9145
        // Overwrite isSynced and return.
3✔
9146
        info.isSynced = height == bestHeight
3✔
9147

3✔
9148
        if !info.isSynced {
6✔
9149
                rpcsLog.Debugf("Blockbeat is not synced to height %v yet",
3✔
9150
                        bestHeight)
3✔
9151
        }
3✔
9152

9153
        return info, nil
3✔
9154
}
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