Skip to content

Commit 8d5fff4

Browse files
committed
graphdb: test querying chans without a policy
In this commit we add TestChanUpdatesInHorizonWithNoPolicies to test that we can query channels with no policy attached to it. We also test that we can query channels with policies alongside those without.
1 parent 15177ef commit 8d5fff4

File tree

2 files changed

+143
-0
lines changed

2 files changed

+143
-0
lines changed

graph/db/graph_sql_test.go

Lines changed: 138 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,138 @@
1+
//go:build test_db_postgres || test_db_sqlite
2+
3+
package graphdb
4+
5+
import (
6+
"testing"
7+
"time"
8+
9+
"github.com/lightningnetwork/lnd/fn/v2"
10+
"github.com/stretchr/testify/require"
11+
)
12+
13+
// TestChanUpdatesInHorizonWithNoPolicies tests that we're able to properly
14+
// retrieve channels with no policies within the time range.
15+
func TestChanUpdatesInHorizonWithNoPolicies(t *testing.T) {
16+
t.Parallel()
17+
ctx := t.Context()
18+
19+
graph := MakeTestGraph(t)
20+
21+
// We'll start by creating two nodes which will seed our test graph.
22+
node1 := createTestVertex(t)
23+
require.NoError(t, graph.AddNode(ctx, node1))
24+
25+
node2 := createTestVertex(t)
26+
require.NoError(t, graph.AddNode(ctx, node2))
27+
28+
// Note: startTime and endTime only works if the channels have
29+
// policies. If not, the channels are included irrespective of the
30+
// time range.
31+
startTime := time.Unix(1234, 0)
32+
endTime := startTime
33+
edges := make([]ChannelEdge, 0, 10)
34+
35+
// We'll now create 10 channels between the two nodes, with no policies.
36+
const numChans = 10
37+
for i := range numChans {
38+
channel, chanID := createEdge(
39+
uint32(i*10), 0, 0, 0, node1, node2,
40+
)
41+
require.NoError(t, graph.AddChannelEdge(ctx, &channel))
42+
43+
// The first 5 channels will have no policies.
44+
if i < numChans/2 {
45+
edges = append(edges, ChannelEdge{
46+
Info: &channel,
47+
})
48+
49+
continue
50+
}
51+
52+
edge1UpdateTime := endTime
53+
edge2UpdateTime := edge1UpdateTime.Add(time.Second)
54+
endTime = endTime.Add(time.Second * 10)
55+
56+
edge1 := newEdgePolicy(
57+
chanID.ToUint64(), edge1UpdateTime.Unix(),
58+
)
59+
edge1.ChannelFlags = 0
60+
edge1.ToNode = node2.PubKeyBytes
61+
edge1.SigBytes = testSig.Serialize()
62+
require.NoError(t, graph.UpdateEdgePolicy(ctx, edge1))
63+
64+
edge2 := newEdgePolicy(
65+
chanID.ToUint64(), edge2UpdateTime.Unix(),
66+
)
67+
edge2.ChannelFlags = 1
68+
edge2.ToNode = node1.PubKeyBytes
69+
edge2.SigBytes = testSig.Serialize()
70+
require.NoError(t, graph.UpdateEdgePolicy(ctx, edge2))
71+
72+
edges = append(edges, ChannelEdge{
73+
Info: &channel,
74+
Policy1: edge1,
75+
Policy2: edge2,
76+
})
77+
}
78+
79+
// With our channels loaded, we'll now start our series of queries.
80+
queryCases := []struct {
81+
start time.Time
82+
end time.Time
83+
resp []ChannelEdge
84+
}{
85+
// If we query for a time range that's strictly below our set
86+
// of updates, then we'll get only the 5 channels with no
87+
// policies.
88+
{
89+
start: time.Unix(100, 0),
90+
end: time.Unix(200, 0),
91+
resp: edges[:5],
92+
},
93+
94+
// If we query for a time range that's well beyond our set of
95+
// updates, we should get only the 5 channels with no
96+
// policies.
97+
{
98+
start: time.Unix(99999, 0),
99+
end: time.Unix(999999, 0),
100+
resp: edges[:5],
101+
},
102+
103+
// If we query for the start time, and 10 seconds directly
104+
// after it, we should only get the 5 channels with no
105+
// policies and one channel with a policy.
106+
{
107+
start: time.Unix(1234, 0),
108+
end: startTime.Add(time.Second * 10),
109+
resp: edges[:6],
110+
},
111+
112+
// If we use the start and end time as is, we should get the
113+
// entire range.
114+
{
115+
start: startTime,
116+
end: endTime,
117+
118+
resp: edges[:10],
119+
},
120+
}
121+
122+
for _, queryCase := range queryCases {
123+
respIter := graph.ChanUpdatesInHorizon(
124+
queryCase.start, queryCase.end,
125+
)
126+
127+
resp, err := fn.CollectErr(respIter)
128+
require.NoError(t, err)
129+
require.Equal(t, len(resp), len(queryCase.resp))
130+
131+
for i := range len(resp) {
132+
chanExp := queryCase.resp[i]
133+
chanRet := resp[i]
134+
135+
require.Equal(t, chanExp.Info, chanRet.Info)
136+
}
137+
}
138+
}

graph/db/sql_store.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1098,6 +1098,11 @@ func (s *SQLStore) updateChanCacheBatch(edgesToCache map[uint64]ChannelEdge) {
10981098
// 5. Update cache after successful batch
10991099
// 6. Repeat with updated pagination cursor until no more results
11001100
//
1101+
// Note: Ideally each channel should have at least one policy. However, if a
1102+
// channel is created and never updated, it will not have any policies.
1103+
// In this case, we'll return the channel with no policies at all regardless of
1104+
// the time range. This helps us prune zombie channels with no policies.
1105+
//
11011106
// NOTE: This is part of the V1Store interface.
11021107
func (s *SQLStore) ChanUpdatesInHorizon(startTime, endTime time.Time,
11031108
opts ...IteratorOption) iter.Seq2[ChannelEdge, error] {

0 commit comments

Comments
 (0)