@@ -90,6 +90,7 @@ type SQLQueries interface {
90
90
GetChannelFeaturesAndExtras (ctx context.Context , channelID int64 ) ([]sqlc.GetChannelFeaturesAndExtrasRow , error )
91
91
HighestSCID (ctx context.Context , version int16 ) ([]byte , error )
92
92
ListChannelsByNodeID (ctx context.Context , arg sqlc.ListChannelsByNodeIDParams ) ([]sqlc.ListChannelsByNodeIDRow , error )
93
+ GetChannelsByPolicyLastUpdateRange (ctx context.Context , arg sqlc.GetChannelsByPolicyLastUpdateRangeParams ) ([]sqlc.GetChannelsByPolicyLastUpdateRangeRow , error )
93
94
94
95
CreateChannelExtraType (ctx context.Context , arg sqlc.CreateChannelExtraTypeParams ) error
95
96
InsertChannelFeature (ctx context.Context , arg sqlc.InsertChannelFeatureParams ) error
@@ -924,6 +925,125 @@ func (s *SQLStore) ForEachNodeChannel(nodePub route.Vertex,
924
925
}, sqldb .NoOpReset )
925
926
}
926
927
928
+ // ChanUpdatesInHorizon returns all the known channel edges which have at least
929
+ // one edge that has an update timestamp within the specified horizon.
930
+ //
931
+ // NOTE: This is part of the V1Store interface.
932
+ func (s * SQLStore ) ChanUpdatesInHorizon (startTime ,
933
+ endTime time.Time ) ([]ChannelEdge , error ) {
934
+
935
+ s .cacheMu .Lock ()
936
+ defer s .cacheMu .Unlock ()
937
+
938
+ var (
939
+ ctx = context .TODO ()
940
+ // To ensure we don't return duplicate ChannelEdges, we'll use
941
+ // an additional map to keep track of the edges already seen to
942
+ // prevent re-adding it.
943
+ edgesSeen = make (map [uint64 ]struct {})
944
+ edgesToCache = make (map [uint64 ]ChannelEdge )
945
+ edges []ChannelEdge
946
+ hits int
947
+ )
948
+ err := s .db .ExecTx (ctx , sqldb .ReadTxOpt (), func (db SQLQueries ) error {
949
+ rows , err := db .GetChannelsByPolicyLastUpdateRange (
950
+ ctx , sqlc.GetChannelsByPolicyLastUpdateRangeParams {
951
+ Version : int16 (ProtocolV1 ),
952
+ StartTime : sqldb .SQLInt64 (startTime .Unix ()),
953
+ EndTime : sqldb .SQLInt64 (endTime .Unix ()),
954
+ },
955
+ )
956
+ if err != nil {
957
+ return err
958
+ }
959
+
960
+ for _ , row := range rows {
961
+ // If we've already retrieved the info and policies for
962
+ // this edge, then we can skip it as we don't need to do
963
+ // so again.
964
+ chanIDInt := byteOrder .Uint64 (row .Channel .Scid )
965
+ if _ , ok := edgesSeen [chanIDInt ]; ok {
966
+ continue
967
+ }
968
+
969
+ if channel , ok := s .chanCache .get (chanIDInt ); ok {
970
+ hits ++
971
+ edgesSeen [chanIDInt ] = struct {}{}
972
+ edges = append (edges , channel )
973
+
974
+ continue
975
+ }
976
+
977
+ node1 , node2 , err := buildNodes (
978
+ ctx , db , row .Node , row .Node_2 ,
979
+ )
980
+ if err != nil {
981
+ return err
982
+ }
983
+
984
+ channel , err := getAndBuildEdgeInfo (
985
+ ctx , db , s .cfg .ChainHash , row .Channel .ID ,
986
+ row .Channel , node1 .PubKeyBytes ,
987
+ node2 .PubKeyBytes ,
988
+ )
989
+ if err != nil {
990
+ return fmt .Errorf ("unable to build channel " +
991
+ "info: %w" , err )
992
+ }
993
+
994
+ dbPol1 , dbPol2 , err := extractChannelPolicies (row )
995
+ if err != nil {
996
+ return fmt .Errorf ("unable to extract channel " +
997
+ "policies: %w" , err )
998
+ }
999
+
1000
+ p1 , p2 , err := getAndBuildChanPolicies (
1001
+ ctx , db , dbPol1 , dbPol2 , channel .ChannelID ,
1002
+ node1 .PubKeyBytes , node2 .PubKeyBytes ,
1003
+ )
1004
+ if err != nil {
1005
+ return fmt .Errorf ("unable to build channel " +
1006
+ "policies: %w" , err )
1007
+ }
1008
+
1009
+ edgesSeen [chanIDInt ] = struct {}{}
1010
+ chanEdge := ChannelEdge {
1011
+ Info : channel ,
1012
+ Policy1 : p1 ,
1013
+ Policy2 : p2 ,
1014
+ Node1 : node1 ,
1015
+ Node2 : node2 ,
1016
+ }
1017
+ edges = append (edges , chanEdge )
1018
+ edgesToCache [chanIDInt ] = chanEdge
1019
+ }
1020
+
1021
+ return nil
1022
+ }, func () {
1023
+ edgesSeen = make (map [uint64 ]struct {})
1024
+ edgesToCache = make (map [uint64 ]ChannelEdge )
1025
+ edges = nil
1026
+ })
1027
+ if err != nil {
1028
+ return nil , fmt .Errorf ("unable to fetch channels: %w" , err )
1029
+ }
1030
+
1031
+ // Insert any edges loaded from disk into the cache.
1032
+ for chanid , channel := range edgesToCache {
1033
+ s .chanCache .insert (chanid , channel )
1034
+ }
1035
+
1036
+ if len (edges ) > 0 {
1037
+ log .Debugf ("ChanUpdatesInHorizon hit percentage: %f (%d/%d)" ,
1038
+ float64 (hits )/ float64 (len (edges )), hits , len (edges ))
1039
+ } else {
1040
+ log .Debugf ("ChanUpdatesInHorizon returned no edges in " +
1041
+ "horizon (%s, %s)" , startTime , endTime )
1042
+ }
1043
+
1044
+ return edges , nil
1045
+ }
1046
+
927
1047
// forEachNodeDirectedChannel iterates through all channels of a given
928
1048
// node, executing the passed callback on the directed edge representing the
929
1049
// channel and its incoming policy. If the node is not found, no error is
@@ -977,12 +1097,7 @@ func forEachNodeDirectedChannel(ctx context.Context, db SQLQueries,
977
1097
err )
978
1098
}
979
1099
980
- edge , err := buildCacheableChannelInfo (
981
- row .Channel , node1 , node2 ,
982
- )
983
- if err != nil {
984
- return err
985
- }
1100
+ edge := buildCacheableChannelInfo (row .Channel , node1 , node2 )
986
1101
987
1102
dbPol1 , dbPol2 , err := extractChannelPolicies (row )
988
1103
if err != nil {
@@ -1286,14 +1401,14 @@ func getNodeByPubKey(ctx context.Context, db SQLQueries,
1286
1401
// provided database channel row and the public keys of the two nodes
1287
1402
// involved in the channel.
1288
1403
func buildCacheableChannelInfo (dbChan sqlc.Channel , node1Pub ,
1289
- node2Pub route.Vertex ) ( * models.CachedEdgeInfo , error ) {
1404
+ node2Pub route.Vertex ) * models.CachedEdgeInfo {
1290
1405
1291
1406
return & models.CachedEdgeInfo {
1292
1407
ChannelID : byteOrder .Uint64 (dbChan .Scid ),
1293
1408
NodeKey1Bytes : node1Pub ,
1294
1409
NodeKey2Bytes : node2Pub ,
1295
1410
Capacity : btcutil .Amount (dbChan .Capacity .Int64 ),
1296
- }, nil
1411
+ }
1297
1412
}
1298
1413
1299
1414
// buildNode constructs a LightningNode instance from the given database node
@@ -2302,17 +2417,76 @@ func buildChanPolicy(dbPolicy sqlc.ChannelPolicy, channelID uint64,
2302
2417
}, nil
2303
2418
}
2304
2419
2420
+ // buildNodes builds the models.LightningNode instances for the
2421
+ // given row which is expected to be a sqlc type that contains node information.
2422
+ func buildNodes (ctx context.Context , db SQLQueries , dbNode1 ,
2423
+ dbNode2 sqlc.Node ) (* models.LightningNode , * models.LightningNode ,
2424
+ error ) {
2425
+
2426
+ node1 , err := buildNode (ctx , db , & dbNode1 )
2427
+ if err != nil {
2428
+ return nil , nil , err
2429
+ }
2430
+
2431
+ node2 , err := buildNode (ctx , db , & dbNode2 )
2432
+ if err != nil {
2433
+ return nil , nil , err
2434
+ }
2435
+
2436
+ return node1 , node2 , nil
2437
+ }
2438
+
2305
2439
// extractChannelPolicies extracts the sqlc.ChannelPolicy records from the give
2306
2440
// row which is expected to be a sqlc type that contains channel policy
2307
2441
// information. It returns two policies, which may be nil if the policy
2308
2442
// information is not present in the row.
2309
2443
//
2310
- //nolint:ll
2444
+ //nolint:ll,dupl
2311
2445
func extractChannelPolicies (row any ) (* sqlc.ChannelPolicy , * sqlc.ChannelPolicy ,
2312
2446
error ) {
2313
2447
2314
2448
var policy1 , policy2 * sqlc.ChannelPolicy
2315
2449
switch r := row .(type ) {
2450
+ case sqlc.GetChannelsByPolicyLastUpdateRangeRow :
2451
+ if r .Policy1ID .Valid {
2452
+ policy1 = & sqlc.ChannelPolicy {
2453
+ ID : r .Policy1ID .Int64 ,
2454
+ Version : r .Policy1Version .Int16 ,
2455
+ ChannelID : r .Channel .ID ,
2456
+ NodeID : r .Policy1NodeID .Int64 ,
2457
+ Timelock : r .Policy1Timelock .Int32 ,
2458
+ FeePpm : r .Policy1FeePpm .Int64 ,
2459
+ BaseFeeMsat : r .Policy1BaseFeeMsat .Int64 ,
2460
+ MinHtlcMsat : r .Policy1MinHtlcMsat .Int64 ,
2461
+ MaxHtlcMsat : r .Policy1MaxHtlcMsat ,
2462
+ LastUpdate : r .Policy1LastUpdate ,
2463
+ InboundBaseFeeMsat : r .Policy1InboundBaseFeeMsat ,
2464
+ InboundFeeRateMilliMsat : r .Policy1InboundFeeRateMilliMsat ,
2465
+ Disabled : r .Policy1Disabled ,
2466
+ Signature : r .Policy1Signature ,
2467
+ }
2468
+ }
2469
+ if r .Policy2ID .Valid {
2470
+ policy2 = & sqlc.ChannelPolicy {
2471
+ ID : r .Policy2ID .Int64 ,
2472
+ Version : r .Policy2Version .Int16 ,
2473
+ ChannelID : r .Channel .ID ,
2474
+ NodeID : r .Policy2NodeID .Int64 ,
2475
+ Timelock : r .Policy2Timelock .Int32 ,
2476
+ FeePpm : r .Policy2FeePpm .Int64 ,
2477
+ BaseFeeMsat : r .Policy2BaseFeeMsat .Int64 ,
2478
+ MinHtlcMsat : r .Policy2MinHtlcMsat .Int64 ,
2479
+ MaxHtlcMsat : r .Policy2MaxHtlcMsat ,
2480
+ LastUpdate : r .Policy2LastUpdate ,
2481
+ InboundBaseFeeMsat : r .Policy2InboundBaseFeeMsat ,
2482
+ InboundFeeRateMilliMsat : r .Policy2InboundFeeRateMilliMsat ,
2483
+ Disabled : r .Policy2Disabled ,
2484
+ Signature : r .Policy2Signature ,
2485
+ }
2486
+ }
2487
+
2488
+ return policy1 , policy2 , nil
2489
+
2316
2490
case sqlc.ListChannelsByNodeIDRow :
2317
2491
if r .Policy1ID .Valid {
2318
2492
policy1 = & sqlc.ChannelPolicy {
0 commit comments