graph/db: add gossip version parameter to ForEachChannel
Update ForEachChannel to accept a gossip version parameter, allowing callers to specify which gossip version's channels should be iterated. This change prepares the graph database for supporting multiple gossip versions while maintaining backward compatibility. The KVStore implementation validates that only GossipVersion1 is requested, returning ErrVersionNotSupportedForKVDB for other versions. The SQLStore implementation validates known versions and passes the version through to the underlying paginated query. Update VersionedGraph to include a ForEachChannel method that automatically uses its configured gossip version, and update the DescribeGraph RPC handler to use the v1Graph instead of the global graphDB.
This commit is contained in:
7 files changed
+92
-65
No files matched your search
+42
-40
@@ -370,8 +370,8 @@ func TestPopulateDBs(t *testing.T) {
|
|||||||
numPolicies = 0
|
numPolicies = 0
|
||||||
)
|
)
|
||||||
err := graph.ForEachChannel(
|
err := graph.ForEachChannel(
|
||||||
ctx, func(info *models.ChannelEdgeInfo,
|
ctx, lnwire.GossipVersion1,
|
||||||
policy,
|
func(info *models.ChannelEdgeInfo, policy,
|
||||||
policy2 *models.ChannelEdgePolicy) error {
|
policy2 *models.ChannelEdgePolicy) error {
|
||||||
|
|
||||||
numChans++
|
numChans++
|
||||||
@@ -497,48 +497,49 @@ func syncGraph(t *testing.T, src, dest *ChannelGraph) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var wgChans sync.WaitGroup
|
var wgChans sync.WaitGroup
|
||||||
err = src.ForEachChannel(ctx, func(info *models.ChannelEdgeInfo,
|
err = src.ForEachChannel(ctx, lnwire.GossipVersion1,
|
||||||
policy1, policy2 *models.ChannelEdgePolicy) error {
|
func(info *models.ChannelEdgeInfo,
|
||||||
|
policy1, policy2 *models.ChannelEdgePolicy) error {
|
||||||
|
|
||||||
// Add each channel & policy. We do this in a goroutine to
|
// Add each channel & policy. We do this in a goroutine
|
||||||
// take advantage of batch processing.
|
// to take advantage of batch processing.
|
||||||
wgChans.Add(1)
|
wgChans.Add(1)
|
||||||
go func() {
|
go func() {
|
||||||
defer wgChans.Done()
|
defer wgChans.Done()
|
||||||
|
|
||||||
err := dest.AddChannelEdge(
|
err := dest.AddChannelEdge(
|
||||||
ctx, info, batch.LazyAdd(),
|
ctx, info, batch.LazyAdd(),
|
||||||
)
|
|
||||||
if !errors.Is(err, ErrEdgeAlreadyExist) {
|
|
||||||
require.NoError(t, err)
|
|
||||||
}
|
|
||||||
|
|
||||||
if policy1 != nil {
|
|
||||||
err = dest.UpdateEdgePolicy(
|
|
||||||
ctx, policy1, batch.LazyAdd(),
|
|
||||||
)
|
)
|
||||||
require.NoError(t, err)
|
if !errors.Is(err, ErrEdgeAlreadyExist) {
|
||||||
}
|
require.NoError(t, err)
|
||||||
|
}
|
||||||
|
|
||||||
if policy2 != nil {
|
if policy1 != nil {
|
||||||
err = dest.UpdateEdgePolicy(
|
err = dest.UpdateEdgePolicy(
|
||||||
ctx, policy2, batch.LazyAdd(),
|
ctx, policy1, batch.LazyAdd(),
|
||||||
)
|
)
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
}
|
}
|
||||||
|
|
||||||
mu.Lock()
|
if policy2 != nil {
|
||||||
total++
|
err = dest.UpdateEdgePolicy(
|
||||||
chunk++
|
ctx, policy2, batch.LazyAdd(),
|
||||||
s.Do(func() {
|
)
|
||||||
reportChanStats()
|
require.NoError(t, err)
|
||||||
chunk = 0
|
}
|
||||||
})
|
|
||||||
mu.Unlock()
|
|
||||||
}()
|
|
||||||
|
|
||||||
return nil
|
mu.Lock()
|
||||||
}, func() {})
|
total++
|
||||||
|
chunk++
|
||||||
|
s.Do(func() {
|
||||||
|
reportChanStats()
|
||||||
|
chunk = 0
|
||||||
|
})
|
||||||
|
mu.Unlock()
|
||||||
|
}()
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}, func() {})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
|
|
||||||
wgChans.Wait()
|
wgChans.Wait()
|
||||||
@@ -638,7 +639,8 @@ func BenchmarkGraphReadMethods(b *testing.B) {
|
|||||||
fn: func(b testing.TB, store Store) {
|
fn: func(b testing.TB, store Store) {
|
||||||
//nolint:ll
|
//nolint:ll
|
||||||
err := store.ForEachChannel(
|
err := store.ForEachChannel(
|
||||||
ctx, func(_ *models.ChannelEdgeInfo,
|
ctx, lnwire.GossipVersion1,
|
||||||
|
func(_ *models.ChannelEdgeInfo,
|
||||||
_ *models.ChannelEdgePolicy,
|
_ *models.ChannelEdgePolicy,
|
||||||
_ *models.ChannelEdgePolicy) error {
|
_ *models.ChannelEdgePolicy) error {
|
||||||
|
|
||||||
@@ -821,7 +823,7 @@ func BenchmarkFindOptimalSQLQueryConfig(b *testing.B) {
|
|||||||
|
|
||||||
//nolint:ll
|
//nolint:ll
|
||||||
err = store.ForEachChannel(
|
err = store.ForEachChannel(
|
||||||
ctx,
|
ctx, lnwire.GossipVersion1,
|
||||||
func(_ *models.ChannelEdgeInfo,
|
func(_ *models.ChannelEdgeInfo,
|
||||||
_,
|
_,
|
||||||
_ *models.ChannelEdgePolicy) error {
|
_ *models.ChannelEdgePolicy) error {
|
||||||
|
|||||||
+12
-3
@@ -642,10 +642,11 @@ func (c *ChannelGraph) IsPublicNode(pubKey [33]byte) (bool, error) {
|
|||||||
|
|
||||||
// ForEachChannel iterates through all channel edges stored within the graph.
|
// ForEachChannel iterates through all channel edges stored within the graph.
|
||||||
func (c *ChannelGraph) ForEachChannel(ctx context.Context,
|
func (c *ChannelGraph) ForEachChannel(ctx context.Context,
|
||||||
cb func(*models.ChannelEdgeInfo, *models.ChannelEdgePolicy,
|
v lnwire.GossipVersion, cb func(*models.ChannelEdgeInfo,
|
||||||
*models.ChannelEdgePolicy) error, reset func()) error {
|
*models.ChannelEdgePolicy, *models.ChannelEdgePolicy) error,
|
||||||
|
reset func()) error {
|
||||||
|
|
||||||
return c.db.ForEachChannel(ctx, cb, reset)
|
return c.db.ForEachChannel(ctx, v, cb, reset)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ForEachChannelCacheable iterates through all channel edges for the cache.
|
// ForEachChannelCacheable iterates through all channel edges for the cache.
|
||||||
@@ -904,6 +905,14 @@ func (c *VersionedGraph) HasChannelEdge(chanID uint64) (bool, bool, error) {
|
|||||||
return c.db.HasChannelEdge(c.v, chanID)
|
return c.db.HasChannelEdge(c.v, chanID)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ForEachChannel iterates through all channel edges stored within the graph.
|
||||||
|
func (c *VersionedGraph) ForEachChannel(ctx context.Context,
|
||||||
|
cb func(*models.ChannelEdgeInfo, *models.ChannelEdgePolicy,
|
||||||
|
*models.ChannelEdgePolicy) error, reset func()) error {
|
||||||
|
|
||||||
|
return c.db.ForEachChannel(ctx, c.v, cb, reset)
|
||||||
|
}
|
||||||
|
|
||||||
// IsPublicNode determines whether the node is seen as public in the graph.
|
// IsPublicNode determines whether the node is seen as public in the graph.
|
||||||
func (c *VersionedGraph) IsPublicNode(pubKey [33]byte) (bool, error) {
|
func (c *VersionedGraph) IsPublicNode(pubKey [33]byte) (bool, error) {
|
||||||
return c.db.IsPublicNode(c.v, pubKey)
|
return c.db.IsPublicNode(c.v, pubKey)
|
||||||
|
|||||||
+11
-8
@@ -1219,7 +1219,8 @@ func TestEdgePolicyCRUD(t *testing.T) {
|
|||||||
// assert that the deserialized policies match the original
|
// assert that the deserialized policies match the original
|
||||||
// ones.
|
// ones.
|
||||||
err := graph.ForEachChannel(
|
err := graph.ForEachChannel(
|
||||||
ctx, func(info *models.ChannelEdgeInfo,
|
ctx, lnwire.GossipVersion1,
|
||||||
|
func(info *models.ChannelEdgeInfo,
|
||||||
policy1 *models.ChannelEdgePolicy,
|
policy1 *models.ChannelEdgePolicy,
|
||||||
policy2 *models.ChannelEdgePolicy) error {
|
policy2 *models.ChannelEdgePolicy) error {
|
||||||
|
|
||||||
@@ -1703,13 +1704,14 @@ func TestGraphTraversal(t *testing.T) {
|
|||||||
// Iterate through all the known channels within the graph DB, once
|
// Iterate through all the known channels within the graph DB, once
|
||||||
// again if the map is empty that indicates that all edges have
|
// again if the map is empty that indicates that all edges have
|
||||||
// properly been reached.
|
// properly been reached.
|
||||||
err = graph.ForEachChannel(ctx, func(ei *models.ChannelEdgeInfo,
|
err = graph.ForEachChannel(ctx, lnwire.GossipVersion1,
|
||||||
_ *models.ChannelEdgePolicy,
|
func(ei *models.ChannelEdgeInfo,
|
||||||
_ *models.ChannelEdgePolicy) error {
|
_ *models.ChannelEdgePolicy,
|
||||||
|
_ *models.ChannelEdgePolicy) error {
|
||||||
|
|
||||||
delete(chanIndex, ei.ChannelID)
|
delete(chanIndex, ei.ChannelID)
|
||||||
return nil
|
return nil
|
||||||
}, func() {})
|
}, func() {})
|
||||||
require.NoError(t, err)
|
require.NoError(t, err)
|
||||||
require.Len(t, chanIndex, 0)
|
require.Len(t, chanIndex, 0)
|
||||||
|
|
||||||
@@ -2005,7 +2007,8 @@ func assertPruneTip(t *testing.T, graph *ChannelGraph,
|
|||||||
func assertNumChans(t *testing.T, graph *ChannelGraph, n int) {
|
func assertNumChans(t *testing.T, graph *ChannelGraph, n int) {
|
||||||
numChans := 0
|
numChans := 0
|
||||||
err := graph.ForEachChannel(
|
err := graph.ForEachChannel(
|
||||||
t.Context(), func(*models.ChannelEdgeInfo,
|
t.Context(), lnwire.GossipVersion1,
|
||||||
|
func(*models.ChannelEdgeInfo,
|
||||||
*models.ChannelEdgePolicy,
|
*models.ChannelEdgePolicy,
|
||||||
*models.ChannelEdgePolicy) error {
|
*models.ChannelEdgePolicy) error {
|
||||||
|
|
||||||
|
|||||||
@@ -162,9 +162,12 @@ type Store interface { //nolint:interfacebloat
|
|||||||
// NOTE: If an edge can't be found, or wasn't advertised, then a nil
|
// NOTE: If an edge can't be found, or wasn't advertised, then a nil
|
||||||
// pointer for that particular channel edge routing policy will be
|
// pointer for that particular channel edge routing policy will be
|
||||||
// passed into the callback.
|
// passed into the callback.
|
||||||
ForEachChannel(ctx context.Context, cb func(*models.ChannelEdgeInfo,
|
//
|
||||||
*models.ChannelEdgePolicy, *models.ChannelEdgePolicy) error,
|
// TODO(elle): add a cross-version iteration API and make this iterate
|
||||||
reset func()) error
|
// over all versions.
|
||||||
|
ForEachChannel(ctx context.Context, v lnwire.GossipVersion,
|
||||||
|
cb func(*models.ChannelEdgeInfo, *models.ChannelEdgePolicy,
|
||||||
|
*models.ChannelEdgePolicy) error, reset func()) error
|
||||||
|
|
||||||
// ForEachChannelCacheable iterates through all the channel edges stored
|
// ForEachChannelCacheable iterates through all the channel edges stored
|
||||||
// within the graph and invokes the passed callback for each edge. The
|
// within the graph and invokes the passed callback for each edge. The
|
||||||
|
|||||||
@@ -411,10 +411,14 @@ func (c *KVStore) AddrsForNode(ctx context.Context, v lnwire.GossipVersion,
|
|||||||
// NOTE: If an edge can't be found, or wasn't advertised, then a nil pointer
|
// NOTE: If an edge can't be found, or wasn't advertised, then a nil pointer
|
||||||
// for that particular channel edge routing policy will be passed into the
|
// for that particular channel edge routing policy will be passed into the
|
||||||
// callback.
|
// callback.
|
||||||
func (c *KVStore) ForEachChannel(_ context.Context,
|
func (c *KVStore) ForEachChannel(_ context.Context, v lnwire.GossipVersion,
|
||||||
cb func(*models.ChannelEdgeInfo, *models.ChannelEdgePolicy,
|
cb func(*models.ChannelEdgeInfo, *models.ChannelEdgePolicy,
|
||||||
*models.ChannelEdgePolicy) error, reset func()) error {
|
*models.ChannelEdgePolicy) error, reset func()) error {
|
||||||
|
|
||||||
|
if v != lnwire.GossipVersion1 {
|
||||||
|
return ErrVersionNotSupportedForKVDB
|
||||||
|
}
|
||||||
|
|
||||||
return forEachChannel(c.db, cb, reset)
|
return forEachChannel(c.db, cb, reset)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+11
-6
@@ -1610,11 +1610,16 @@ func (s *SQLStore) ForEachChannelCacheable(cb func(*models.CachedEdgeInfo,
|
|||||||
//
|
//
|
||||||
// NOTE: part of the Store interface.
|
// NOTE: part of the Store interface.
|
||||||
func (s *SQLStore) ForEachChannel(ctx context.Context,
|
func (s *SQLStore) ForEachChannel(ctx context.Context,
|
||||||
cb func(*models.ChannelEdgeInfo, *models.ChannelEdgePolicy,
|
v lnwire.GossipVersion, cb func(*models.ChannelEdgeInfo,
|
||||||
*models.ChannelEdgePolicy) error, reset func()) error {
|
*models.ChannelEdgePolicy, *models.ChannelEdgePolicy) error,
|
||||||
|
reset func()) error {
|
||||||
|
|
||||||
|
if !isKnownGossipVersion(v) {
|
||||||
|
return fmt.Errorf("unsupported gossip version: %d", v)
|
||||||
|
}
|
||||||
|
|
||||||
return s.db.ExecTx(ctx, sqldb.ReadTxOpt(), func(db SQLQueries) error {
|
return s.db.ExecTx(ctx, sqldb.ReadTxOpt(), func(db SQLQueries) error {
|
||||||
return forEachChannelWithPolicies(ctx, db, s.cfg, cb)
|
return forEachChannelWithPolicies(ctx, db, s.cfg, v, cb)
|
||||||
}, reset)
|
}, reset)
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -5973,8 +5978,8 @@ func forEachNodePaginated(ctx context.Context, cfg *sqldb.QueryConfig,
|
|||||||
// forEachChannelWithPolicies executes a paginated query to process each channel
|
// forEachChannelWithPolicies executes a paginated query to process each channel
|
||||||
// with policies in the graph.
|
// with policies in the graph.
|
||||||
func forEachChannelWithPolicies(ctx context.Context, db SQLQueries,
|
func forEachChannelWithPolicies(ctx context.Context, db SQLQueries,
|
||||||
cfg *SQLStoreConfig, processChannel func(*models.ChannelEdgeInfo,
|
cfg *SQLStoreConfig, v lnwire.GossipVersion,
|
||||||
*models.ChannelEdgePolicy,
|
processChannel func(*models.ChannelEdgeInfo, *models.ChannelEdgePolicy,
|
||||||
*models.ChannelEdgePolicy) error) error {
|
*models.ChannelEdgePolicy) error) error {
|
||||||
|
|
||||||
type channelBatchIDs struct {
|
type channelBatchIDs struct {
|
||||||
@@ -5988,7 +5993,7 @@ func forEachChannelWithPolicies(ctx context.Context, db SQLQueries,
|
|||||||
|
|
||||||
return db.ListChannelsWithPoliciesPaginated(
|
return db.ListChannelsWithPoliciesPaginated(
|
||||||
ctx, sqlc.ListChannelsWithPoliciesPaginatedParams{
|
ctx, sqlc.ListChannelsWithPoliciesPaginatedParams{
|
||||||
Version: int16(lnwire.GossipVersion1),
|
Version: int16(v),
|
||||||
ID: lastID,
|
ID: lastID,
|
||||||
Limit: limit,
|
Limit: limit,
|
||||||
},
|
},
|
||||||
|
|||||||
+5
-4
@@ -6853,10 +6853,11 @@ func (r *rpcServer) DescribeGraph(ctx context.Context,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Obtain the pointer to the global singleton channel graph, this will
|
// Obtain the pointer to the V1 channel graph. This will provide a
|
||||||
// provide a consistent view of the graph due to bolt db's
|
// consistent view of the graph due to bolt db's transactional model.
|
||||||
// transactional model.
|
//
|
||||||
graph := r.server.graphDB
|
// TODO(elle): switch to a cross-version graph view when available.
|
||||||
|
graph := r.server.v1Graph
|
||||||
|
|
||||||
// First iterate through all the known nodes (connected or unconnected
|
// First iterate through all the known nodes (connected or unconnected
|
||||||
// within the graph), collating their current state into the RPC
|
// within the graph), collating their current state into the RPC
|
||||||
|
|||||||
Reference in new issue
Block a user