@@ -108,6 +108,14 @@ type SQLQueries interface {
108
108
InsertChanPolicyExtraType (ctx context.Context , arg sqlc.InsertChanPolicyExtraTypeParams ) error
109
109
GetChannelPolicyExtraTypes (ctx context.Context , arg sqlc.GetChannelPolicyExtraTypesParams ) ([]sqlc.GetChannelPolicyExtraTypesRow , error )
110
110
DeleteChannelPolicyExtraTypes (ctx context.Context , channelPolicyID int64 ) error
111
+
112
+ /*
113
+ Zombie index queries.
114
+ */
115
+ UpsertZombieChannel (ctx context.Context , arg sqlc.UpsertZombieChannelParams ) error
116
+ GetZombieChannel (ctx context.Context , arg sqlc.GetZombieChannelParams ) (sqlc.ZombieChannel , error )
117
+ CountZombieChannels (ctx context.Context , version int16 ) (int64 , error )
118
+ DeleteZombieChannel (ctx context.Context , arg sqlc.DeleteZombieChannelParams ) (sql.Result , error )
111
119
}
112
120
113
121
// BatchedSQLQueries is a version of SQLQueries that's capable of batched
@@ -1390,6 +1398,160 @@ func (s *SQLStore) FilterChannelRange(startHeight, endHeight uint32,
1390
1398
}), nil
1391
1399
}
1392
1400
1401
+ // MarkEdgeZombie attempts to mark a channel identified by its channel ID as a
1402
+ // zombie. This method is used on an ad-hoc basis, when channels need to be
1403
+ // marked as zombies outside the normal pruning cycle.
1404
+ //
1405
+ // NOTE: part of the V1Store interface.
1406
+ func (s * SQLStore ) MarkEdgeZombie (chanID uint64 ,
1407
+ pubKey1 , pubKey2 [33 ]byte ) error {
1408
+
1409
+ ctx := context .TODO ()
1410
+
1411
+ s .cacheMu .Lock ()
1412
+ defer s .cacheMu .Unlock ()
1413
+
1414
+ chanIDB := channelIDToBytes (chanID )
1415
+
1416
+ err := s .db .ExecTx (ctx , sqldb .WriteTxOpt (), func (db SQLQueries ) error {
1417
+ return db .UpsertZombieChannel (
1418
+ ctx , sqlc.UpsertZombieChannelParams {
1419
+ Version : int16 (ProtocolV1 ),
1420
+ Scid : chanIDB [:],
1421
+ NodeKey1 : pubKey1 [:],
1422
+ NodeKey2 : pubKey2 [:],
1423
+ },
1424
+ )
1425
+ }, sqldb .NoOpReset )
1426
+ if err != nil {
1427
+ return fmt .Errorf ("unable to upsert zombie channel " +
1428
+ "(channel_id=%d): %w" , chanID , err )
1429
+ }
1430
+
1431
+ s .rejectCache .remove (chanID )
1432
+ s .chanCache .remove (chanID )
1433
+
1434
+ return nil
1435
+ }
1436
+
1437
+ // MarkEdgeLive clears an edge from our zombie index, deeming it as live.
1438
+ //
1439
+ // NOTE: part of the V1Store interface.
1440
+ func (s * SQLStore ) MarkEdgeLive (chanID uint64 ) error {
1441
+ s .cacheMu .Lock ()
1442
+ defer s .cacheMu .Unlock ()
1443
+
1444
+ var (
1445
+ ctx = context .TODO ()
1446
+ chanIDB = channelIDToBytes (chanID )
1447
+ )
1448
+
1449
+ err := s .db .ExecTx (ctx , sqldb .WriteTxOpt (), func (db SQLQueries ) error {
1450
+ res , err := db .DeleteZombieChannel (
1451
+ ctx , sqlc.DeleteZombieChannelParams {
1452
+ Scid : chanIDB [:],
1453
+ Version : int16 (ProtocolV1 ),
1454
+ },
1455
+ )
1456
+ if err != nil {
1457
+ return fmt .Errorf ("unable to delete zombie channel: %w" ,
1458
+ err )
1459
+ }
1460
+
1461
+ rows , err := res .RowsAffected ()
1462
+ if err != nil {
1463
+ return err
1464
+ }
1465
+
1466
+ if rows == 0 {
1467
+ return ErrZombieEdgeNotFound
1468
+ } else if rows > 1 {
1469
+ return fmt .Errorf ("deleted %d zombie rows, " +
1470
+ "expected 1" , rows )
1471
+ }
1472
+
1473
+ return nil
1474
+ }, sqldb .NoOpReset )
1475
+ if err != nil {
1476
+ return fmt .Errorf ("unable to mark edge live " +
1477
+ "(channel_id=%d): %w" , chanID , err )
1478
+ }
1479
+
1480
+ s .rejectCache .remove (chanID )
1481
+ s .chanCache .remove (chanID )
1482
+
1483
+ return err
1484
+ }
1485
+
1486
+ // IsZombieEdge returns whether the edge is considered zombie. If it is a
1487
+ // zombie, then the two node public keys corresponding to this edge are also
1488
+ // returned.
1489
+ //
1490
+ // NOTE: part of the V1Store interface.
1491
+ func (s * SQLStore ) IsZombieEdge (chanID uint64 ) (bool , [33 ]byte , [33 ]byte ) {
1492
+ var (
1493
+ ctx = context .TODO ()
1494
+ isZombie bool
1495
+ pubKey1 , pubKey2 route.Vertex
1496
+ chanIDB = channelIDToBytes (chanID )
1497
+ )
1498
+
1499
+ err := s .db .ExecTx (ctx , sqldb .ReadTxOpt (), func (db SQLQueries ) error {
1500
+ zombie , err := db .GetZombieChannel (
1501
+ ctx , sqlc.GetZombieChannelParams {
1502
+ Scid : chanIDB [:],
1503
+ Version : int16 (ProtocolV1 ),
1504
+ },
1505
+ )
1506
+ if errors .Is (err , sql .ErrNoRows ) {
1507
+ return nil
1508
+ }
1509
+ if err != nil {
1510
+ return fmt .Errorf ("unable to fetch zombie channel: %w" ,
1511
+ err )
1512
+ }
1513
+
1514
+ copy (pubKey1 [:], zombie .NodeKey1 )
1515
+ copy (pubKey2 [:], zombie .NodeKey2 )
1516
+ isZombie = true
1517
+
1518
+ return nil
1519
+ }, sqldb .NoOpReset )
1520
+ if err != nil {
1521
+ // TODO(elle): update the IsZombieEdge method to return an
1522
+ // error.
1523
+ return false , route.Vertex {}, route.Vertex {}
1524
+ }
1525
+
1526
+ return isZombie , pubKey1 , pubKey2
1527
+ }
1528
+
1529
+ // NumZombies returns the current number of zombie channels in the graph.
1530
+ //
1531
+ // NOTE: part of the V1Store interface.
1532
+ func (s * SQLStore ) NumZombies () (uint64 , error ) {
1533
+ var (
1534
+ ctx = context .TODO ()
1535
+ numZombies uint64
1536
+ )
1537
+ err := s .db .ExecTx (ctx , sqldb .ReadTxOpt (), func (db SQLQueries ) error {
1538
+ count , err := db .CountZombieChannels (ctx , int16 (ProtocolV1 ))
1539
+ if err != nil {
1540
+ return fmt .Errorf ("unable to count zombie channels: %w" ,
1541
+ err )
1542
+ }
1543
+
1544
+ numZombies = uint64 (count )
1545
+
1546
+ return nil
1547
+ }, sqldb .NoOpReset )
1548
+ if err != nil {
1549
+ return 0 , fmt .Errorf ("unable to count zombies: %w" , err )
1550
+ }
1551
+
1552
+ return numZombies , nil
1553
+ }
1554
+
1393
1555
// forEachNodeDirectedChannel iterates through all channels of a given
1394
1556
// node, executing the passed callback on the directed edge representing the
1395
1557
// channel and its incoming policy. If the node is not found, no error is
0 commit comments