diff --git a/graph/db/graph.go b/graph/db/graph.go index f564d8884..be0ac82d0 100644 --- a/graph/db/graph.go +++ b/graph/db/graph.go @@ -717,13 +717,25 @@ func (c *ChannelGraph) ChanUpdatesInHorizon(ctx context.Context, return c.db.ChanUpdatesInHorizon(ctx, startTime, endTime, opts...) } -// FilterChannelRange returns channel IDs within the passed block height range. +// FilterChannelRange returns channel IDs within the passed block height range +// for the given gossip version. func (c *ChannelGraph) FilterChannelRange(ctx context.Context, - startHeight, endHeight uint32, withTimestamps bool) ( - []BlockChannelRange, error) { + v lnwire.GossipVersion, startHeight, endHeight uint32, + withTimestamps bool) ([]BlockChannelRange, error) { return c.db.FilterChannelRange( - ctx, startHeight, endHeight, withTimestamps, + ctx, v, startHeight, endHeight, withTimestamps, + ) +} + +// FilterChannelRange returns channel IDs within the passed block height range +// for this graph's gossip version. +func (c *VersionedGraph) FilterChannelRange(ctx context.Context, + startHeight, endHeight uint32, + withTimestamps bool) ([]BlockChannelRange, error) { + + return c.db.FilterChannelRange( + ctx, c.v, startHeight, endHeight, withTimestamps, ) } diff --git a/graph/db/graph_test.go b/graph/db/graph_test.go index 90a2fc593..a7bc4d3ad 100644 --- a/graph/db/graph_test.go +++ b/graph/db/graph_test.go @@ -3505,7 +3505,9 @@ func TestFilterChannelRange(t *testing.T) { // If we try to filter a channel range before we have any channels // inserted, we should get an empty slice of results. - resp, err := graph.FilterChannelRange(ctx, 10, 100, false) + resp, err := graph.FilterChannelRange( + ctx, lnwire.GossipVersion1, 10, 100, false, + ) require.NoError(t, err) require.Empty(t, resp) @@ -3676,7 +3678,8 @@ func TestFilterChannelRange(t *testing.T) { // First, do the query without requesting timestamps. resp, err := graph.FilterChannelRange( - ctx, test.startHeight, test.endHeight, false, + ctx, lnwire.GossipVersion1, test.startHeight, + test.endHeight, false, ) require.NoError(t, err) @@ -3690,7 +3693,8 @@ func TestFilterChannelRange(t *testing.T) { // Now, query the timestamps as well. resp, err = graph.FilterChannelRange( - ctx, test.startHeight, test.endHeight, true, + ctx, lnwire.GossipVersion1, test.startHeight, + test.endHeight, true, ) require.NoError(t, err) @@ -3705,6 +3709,29 @@ func TestFilterChannelRange(t *testing.T) { } } +// TestFilterChannelRangeVersionGuard checks that FilterChannelRange correctly +// handles version-specific requests. For gossip v1, the KV store returns +// results as normal; for v2, the KV store returns +// ErrVersionNotSupportedForKVDB while the SQL store returns empty results +// (a v2-aware query is a follow-up). +func TestFilterChannelRangeVersionGuard(t *testing.T) { + t.Parallel() + ctx := t.Context() + + store := NewTestDB(t) + + _, err := store.FilterChannelRange( + ctx, lnwire.GossipVersion2, 0, 1000, false, + ) + + // The KV store does not support v2 and must return the sentinel error. + // The SQL store accepts any known version (returning empty results + // since no v2 channels have been added). + if err != nil { + require.ErrorIs(t, err, ErrVersionNotSupportedForKVDB) + } +} + // TestFetchChanInfos tests that we're able to properly retrieve the full set // of ChannelEdge structs for a given set of short channel ID's. func testFetchChanInfos(t *testing.T, v lnwire.GossipVersion) { diff --git a/graph/db/interfaces.go b/graph/db/interfaces.go index e701e61c8..00ced9c8f 100644 --- a/graph/db/interfaces.go +++ b/graph/db/interfaces.go @@ -273,15 +273,15 @@ type Store interface { //nolint:interfacebloat error) // FilterChannelRange returns the channel ID's of all known channels - // which were mined in a block height within the passed range. The - // channel IDs are grouped by their common block height. This method can - // be used to quickly share with a peer the set of channels we know of - // within a particular range to catch them up after a period of time - // offline. If withTimestamps is true then the timestamp info of the - // latest received channel update messages of the channel will be - // included in the response. - FilterChannelRange(ctx context.Context, startHeight, - endHeight uint32, + // which were mined in a block height within the passed range for the + // given gossip version. The channel IDs are grouped by their common + // block height. This method can be used to quickly share with a peer + // the set of channels we know of within a particular range to catch + // them up after a period of time offline. If withTimestamps is true + // then the timestamp info of the latest received channel update + // messages of the channel will be included in the response. + FilterChannelRange(ctx context.Context, v lnwire.GossipVersion, + startHeight, endHeight uint32, withTimestamps bool) ([]BlockChannelRange, error) // FetchChanInfos returns the set of channel edges that correspond to diff --git a/graph/db/kv_store.go b/graph/db/kv_store.go index cd8a9289d..8e6ba3b89 100644 --- a/graph/db/kv_store.go +++ b/graph/db/kv_store.go @@ -2859,8 +2859,13 @@ type BlockChannelRange struct { // up after a period of time offline. If withTimestamps is true then the // timestamp info of the latest received channel update messages of the channel // will be included in the response. -func (c *KVStore) FilterChannelRange(_ context.Context, startHeight, - endHeight uint32, withTimestamps bool) ([]BlockChannelRange, error) { +func (c *KVStore) FilterChannelRange(_ context.Context, + v lnwire.GossipVersion, startHeight, endHeight uint32, + withTimestamps bool) ([]BlockChannelRange, error) { + + if v != lnwire.GossipVersion1 { + return nil, ErrVersionNotSupportedForKVDB + } startChanID := &lnwire.ShortChannelID{ BlockHeight: startHeight, diff --git a/graph/db/sql_store.go b/graph/db/sql_store.go index c9e738436..c2d8a7076 100644 --- a/graph/db/sql_store.go +++ b/graph/db/sql_store.go @@ -1664,8 +1664,9 @@ func (s *SQLStore) ForEachChannel(ctx context.Context, // will be included in the response. // // NOTE: This is part of the Store interface. -func (s *SQLStore) FilterChannelRange(ctx context.Context, startHeight, - endHeight uint32, withTimestamps bool) ([]BlockChannelRange, error) { +func (s *SQLStore) FilterChannelRange(ctx context.Context, + v lnwire.GossipVersion, startHeight, endHeight uint32, + withTimestamps bool) ([]BlockChannelRange, error) { var ( startSCID = &lnwire.ShortChannelID{ @@ -1687,6 +1688,7 @@ func (s *SQLStore) FilterChannelRange(ctx context.Context, startHeight, // and add those timestamps to the collected channel. channelsPerBlock := make(map[uint32][]ChannelUpdateInfo) err := s.db.ExecTx(ctx, sqldb.ReadTxOpt(), func(db SQLQueries) error { + // TODO(elle): replace with a version-aware query. dbChans, err := db.GetPublicV1ChannelsBySCID( ctx, sqlc.GetPublicV1ChannelsBySCIDParams{ StartScid: chanIDStart, @@ -1699,6 +1701,10 @@ func (s *SQLStore) FilterChannelRange(ctx context.Context, startHeight, } for _, dbChan := range dbChans { + if v != lnwire.GossipVersion(dbChan.Version) { + continue + } + cid := lnwire.NewShortChanIDFromInt( byteOrder.Uint64(dbChan.Scid), ) @@ -1718,7 +1724,7 @@ func (s *SQLStore) FilterChannelRange(ctx context.Context, startHeight, //nolint:ll node1Policy, err := db.GetChannelPolicyByChannelAndNode( ctx, sqlc.GetChannelPolicyByChannelAndNodeParams{ - Version: int16(lnwire.GossipVersion1), + Version: int16(v), ChannelID: dbChan.ID, NodeID: dbChan.NodeID1, }, @@ -1735,7 +1741,7 @@ func (s *SQLStore) FilterChannelRange(ctx context.Context, startHeight, //nolint:ll node2Policy, err := db.GetChannelPolicyByChannelAndNode( ctx, sqlc.GetChannelPolicyByChannelAndNodeParams{ - Version: int16(lnwire.GossipVersion1), + Version: int16(v), ChannelID: dbChan.ID, NodeID: dbChan.NodeID2, },