diff --git a/graph/db/graph_test.go b/graph/db/graph_test.go index 12d9ef109..97da79dbd 100644 --- a/graph/db/graph_test.go +++ b/graph/db/graph_test.go @@ -4325,7 +4325,7 @@ func TestGraphLoading(t *testing.T) { func TestClosedScid(t *testing.T) { t.Parallel() - graph := MakeTestGraph(t) + graph := MakeTestGraphNew(t) scid := lnwire.ShortChannelID{} diff --git a/graph/db/sql_store.go b/graph/db/sql_store.go index bfd2b0125..183d2f13c 100644 --- a/graph/db/sql_store.go +++ b/graph/db/sql_store.go @@ -137,6 +137,12 @@ type SQLQueries interface { GetPruneTip(ctx context.Context) (sqlc.PruneLog, error) UpsertPruneLogEntry(ctx context.Context, arg sqlc.UpsertPruneLogEntryParams) error DeletePruneLogEntriesInRange(ctx context.Context, arg sqlc.DeletePruneLogEntriesInRangeParams) error + + /* + Closed SCID table queries. + */ + InsertClosedChannel(ctx context.Context, scid []byte) error + IsClosedChannel(ctx context.Context, scid []byte) (bool, error) } // BatchedSQLQueries is a version of SQLQueries that's capable of batched @@ -2624,6 +2630,50 @@ func (s *SQLStore) AddEdgeProof(scid lnwire.ShortChannelID, return nil } +// PutClosedScid stores a SCID for a closed channel in the database. This is so +// that we can ignore channel announcements that we know to be closed without +// having to validate them and fetch a block. +// +// NOTE: part of the V1Store interface. +func (s *SQLStore) PutClosedScid(scid lnwire.ShortChannelID) error { + var ( + ctx = context.TODO() + chanIDB = channelIDToBytes(scid.ToUint64()) + ) + + return s.db.ExecTx(ctx, sqldb.WriteTxOpt(), func(db SQLQueries) error { + return db.InsertClosedChannel(ctx, chanIDB[:]) + }, sqldb.NoOpReset) +} + +// IsClosedScid checks whether a channel identified by the passed in scid is +// closed. This helps avoid having to perform expensive validation checks. +// +// NOTE: part of the V1Store interface. +func (s *SQLStore) IsClosedScid(scid lnwire.ShortChannelID) (bool, error) { + var ( + ctx = context.TODO() + isClosed bool + chanIDB = channelIDToBytes(scid.ToUint64()) + ) + err := s.db.ExecTx(ctx, sqldb.ReadTxOpt(), func(db SQLQueries) error { + var err error + isClosed, err = db.IsClosedChannel(ctx, chanIDB[:]) + if err != nil { + return fmt.Errorf("unable to fetch closed channel: %w", + err) + } + + return nil + }, sqldb.NoOpReset) + if err != nil { + return false, fmt.Errorf("unable to fetch closed channel: %w", + err) + } + + return isClosed, nil +} + // forEachNodeDirectedChannel iterates through all channels of a given // node, executing the passed callback on the directed edge representing the // channel and its incoming policy. If the node is not found, no error is diff --git a/sqldb/sqlc/graph.sql.go b/sqldb/sqlc/graph.sql.go index 2f0380294..0387f612e 100644 --- a/sqldb/sqlc/graph.sql.go +++ b/sqldb/sqlc/graph.sql.go @@ -1555,6 +1555,22 @@ func (q *Queries) InsertChannelFeature(ctx context.Context, arg InsertChannelFea return err } +const insertClosedChannel = `-- name: InsertClosedChannel :exec +/* ───────────────────────────────────────────── + closed_scid table queries + ────────────────────────────────────────────- +*/ + +INSERT INTO closed_scids (scid) +VALUES ($1) +ON CONFLICT (scid) DO NOTHING +` + +func (q *Queries) InsertClosedChannel(ctx context.Context, scid []byte) error { + _, err := q.db.ExecContext(ctx, insertClosedChannel, scid) + return err +} + const insertNodeAddress = `-- name: InsertNodeAddress :exec /* ───────────────────────────────────────────── node_addresses table queries @@ -1611,6 +1627,21 @@ func (q *Queries) InsertNodeFeature(ctx context.Context, arg InsertNodeFeaturePa return err } +const isClosedChannel = `-- name: IsClosedChannel :one +SELECT EXISTS ( + SELECT 1 + FROM closed_scids + WHERE scid = $1 +) +` + +func (q *Queries) IsClosedChannel(ctx context.Context, scid []byte) (bool, error) { + row := q.db.QueryRowContext(ctx, isClosedChannel, scid) + var exists bool + err := row.Scan(&exists) + return exists, err +} + const isPublicV1Node = `-- name: IsPublicV1Node :one SELECT EXISTS ( SELECT 1 diff --git a/sqldb/sqlc/querier.go b/sqldb/sqlc/querier.go index f166904da..28df66d90 100644 --- a/sqldb/sqlc/querier.go +++ b/sqldb/sqlc/querier.go @@ -80,6 +80,7 @@ type Querier interface { InsertAMPSubInvoiceHTLC(ctx context.Context, arg InsertAMPSubInvoiceHTLCParams) error InsertChanPolicyExtraType(ctx context.Context, arg InsertChanPolicyExtraTypeParams) error InsertChannelFeature(ctx context.Context, arg InsertChannelFeatureParams) error + InsertClosedChannel(ctx context.Context, scid []byte) error InsertInvoice(ctx context.Context, arg InsertInvoiceParams) (int64, error) InsertInvoiceFeature(ctx context.Context, arg InsertInvoiceFeatureParams) error InsertInvoiceHTLC(ctx context.Context, arg InsertInvoiceHTLCParams) (int64, error) @@ -88,6 +89,7 @@ type Querier interface { InsertMigratedInvoice(ctx context.Context, arg InsertMigratedInvoiceParams) (int64, error) InsertNodeAddress(ctx context.Context, arg InsertNodeAddressParams) error InsertNodeFeature(ctx context.Context, arg InsertNodeFeatureParams) error + IsClosedChannel(ctx context.Context, scid []byte) (bool, error) IsPublicV1Node(ctx context.Context, pubKey []byte) (bool, error) IsZombieChannel(ctx context.Context, arg IsZombieChannelParams) (bool, error) ListChannelsByNodeID(ctx context.Context, arg ListChannelsByNodeIDParams) ([]ListChannelsByNodeIDRow, error) diff --git a/sqldb/sqlc/queries/graph.sql b/sqldb/sqlc/queries/graph.sql index 6281ea0ab..681f80def 100644 --- a/sqldb/sqlc/queries/graph.sql +++ b/sqldb/sqlc/queries/graph.sql @@ -709,3 +709,20 @@ LIMIT 1; DELETE FROM prune_log WHERE block_height >= @start_height AND block_height <= @end_height; + +/* ───────────────────────────────────────────── + closed_scid table queries + ────────────────────────────────────────────- +*/ + +-- name: InsertClosedChannel :exec +INSERT INTO closed_scids (scid) +VALUES ($1) +ON CONFLICT (scid) DO NOTHING; + +-- name: IsClosedChannel :one +SELECT EXISTS ( + SELECT 1 + FROM closed_scids + WHERE scid = $1 +);