Skip to content

Commit 00b6e02

Browse files
committed
graph/db+sqldb: implement various zombie index methods
Here we implement the SQLStore methods: - MarkEdgeZombie - MarkEdgeLive - IsZombieEdge - NumZombies These will be tested in the next commit as one more method implementation is required.
1 parent 137fc09 commit 00b6e02

File tree

4 files changed

+282
-0
lines changed

4 files changed

+282
-0
lines changed

graph/db/sql_store.go

Lines changed: 162 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -108,6 +108,14 @@ type SQLQueries interface {
108108
InsertChanPolicyExtraType(ctx context.Context, arg sqlc.InsertChanPolicyExtraTypeParams) error
109109
GetChannelPolicyExtraTypes(ctx context.Context, arg sqlc.GetChannelPolicyExtraTypesParams) ([]sqlc.GetChannelPolicyExtraTypesRow, error)
110110
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)
111119
}
112120

113121
// BatchedSQLQueries is a version of SQLQueries that's capable of batched
@@ -1390,6 +1398,160 @@ func (s *SQLStore) FilterChannelRange(startHeight, endHeight uint32,
13901398
}), nil
13911399
}
13921400

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+
13931555
// forEachNodeDirectedChannel iterates through all channels of a given
13941556
// node, executing the passed callback on the directed edge representing the
13951557
// channel and its incoming policy. If the node is not found, no error is

sqldb/sqlc/graph.sql.go

Lines changed: 85 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

sqldb/sqlc/querier.go

Lines changed: 4 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

sqldb/sqlc/queries/graph.sql

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -460,3 +460,34 @@ WHERE cp.id = $1 OR cp.id = $2;
460460
-- name: DeleteChannelPolicyExtraTypes :exec
461461
DELETE FROM channel_policy_extra_types
462462
WHERE channel_policy_id = $1;
463+
464+
/* ─────────────────────────────────────────────
465+
zombie_channels table queries
466+
─────────────────────────────────────────────
467+
*/
468+
469+
-- name: UpsertZombieChannel :exec
470+
INSERT INTO zombie_channels (scid, version, node_key_1, node_key_2)
471+
VALUES ($1, $2, $3, $4)
472+
ON CONFLICT (scid, version)
473+
DO UPDATE SET
474+
-- If a conflict exists for the SCID and version pair, then we
475+
-- update the node keys.
476+
node_key_1 = COALESCE(EXCLUDED.node_key_1, zombie_channels.node_key_1),
477+
node_key_2 = COALESCE(EXCLUDED.node_key_2, zombie_channels.node_key_2);
478+
479+
-- name: DeleteZombieChannel :execresult
480+
DELETE FROM zombie_channels
481+
WHERE scid = $1
482+
AND version = $2;
483+
484+
-- name: CountZombieChannels :one
485+
SELECT COUNT(*)
486+
FROM zombie_channels
487+
WHERE version = $1;
488+
489+
-- name: GetZombieChannel :one
490+
SELECT *
491+
FROM zombie_channels
492+
WHERE scid = $1
493+
AND version = $2;

0 commit comments

Comments
 (0)