channeldb+discovery: use timestamps to maybe revive zombie

This commit is contained in:
Elle Mouton committed 2023-12-11 09:12:05 +02:00
1 parent ebe0755a97
commit a242ad5acb
5 files changed
+212 -53

No files matched your search

+40 -8
View File
@@ -2086,10 +2086,12 @@ func (c *ChannelGraph) NodeUpdatesInHorizon(startTime,
// words, we perform a set difference of our set of chan ID's and the ones
// passed in. This method can be used by callers to determine the set of
// channels another peer knows of that we don't.
func (c *ChannelGraph) FilterKnownChanIDs(chanIDs []uint64) ([]uint64, error) {
func (c *ChannelGraph) FilterKnownChanIDs(chansInfo []ChannelUpdateInfo,
isZombieChan func(time.Time, time.Time) bool) ([]uint64, error) {
var newChanIDs []uint64
err := kvdb.View(c.db, func(tx kvdb.RTx) error {
err := kvdb.Update(c.db, func(tx kvdb.RwTx) error {
edges := tx.ReadBucket(edgeBucket)
if edges == nil {
return ErrGraphNoEdgesFound
@@ -2107,8 +2109,9 @@ func (c *ChannelGraph) FilterKnownChanIDs(chanIDs []uint64) ([]uint64, error) {
// We'll run through the set of chanIDs and collate only the
// set of channel that are unable to be found within our db.
var cidBytes [8]byte
for _, cid := range chanIDs {
byteOrder.PutUint64(cidBytes[:], cid)
for _, info := range chansInfo {
scid := info.ShortChannelID.ToUint64()
byteOrder.PutUint64(cidBytes[:], scid)
// If the edge is already known, skip it.
if v := edgeIndex.Get(cidBytes[:]); v != nil {
@@ -2117,13 +2120,37 @@ func (c *ChannelGraph) FilterKnownChanIDs(chanIDs []uint64) ([]uint64, error) {
// If the edge is a known zombie, skip it.
if zombieIndex != nil {
isZombie, _, _ := isZombieEdge(zombieIndex, cid)
if isZombie {
isZombie, _, _ := isZombieEdge(
zombieIndex, scid,
)
isStillZombie := isZombieChan(
info.Node1UpdateTimestamp,
info.Node2UpdateTimestamp,
)
switch {
// If the edge is a known zombie and if we
// would still consider it a zombie given the
// latest update timestamps, then we skip this
// channel.
case isZombie && isStillZombie:
continue
// Otherwise, if we have marked it as a zombie
// but the latest update timestamps could bring
// it back from the dead, then we mark it alive,
// and we let it be added to the set of IDs to
// query our peer for.
case isZombie && !isStillZombie:
err := c.markEdgeLive(tx, scid)
if err != nil {
return err
}
}
}
newChanIDs = append(newChanIDs, cid)
newChanIDs = append(newChanIDs, scid)
}
return nil
@@ -2134,7 +2161,12 @@ func (c *ChannelGraph) FilterKnownChanIDs(chanIDs []uint64) ([]uint64, error) {
// If we don't know of any edges yet, then we'll return the entire set
// of chan IDs specified.
case err == ErrGraphNoEdgesFound:
return chanIDs, nil
ogChanIDs := make([]uint64, len(chansInfo))
for i, info := range chansInfo {
ogChanIDs[i] = info.ShortChannelID.ToUint64()
}
return ogChanIDs, nil
case err != nil:
return nil, err
+85 -21
View File
@@ -1928,14 +1928,32 @@ func TestFilterKnownChanIDs(t *testing.T) {
graph, err := MakeTestGraph(t)
require.NoError(t, err, "unable to make test database")
isZombieUpdate := func(updateTime1 time.Time,
updateTime2 time.Time) bool {
return true
}
var (
scid1 = lnwire.ShortChannelID{BlockHeight: 1}
scid2 = lnwire.ShortChannelID{BlockHeight: 2}
scid3 = lnwire.ShortChannelID{BlockHeight: 3}
)
// If we try to filter out a set of channel ID's before we even know of
// any channels, then we should get the entire set back.
preChanIDs := []uint64{1, 2, 3, 4}
filteredIDs, err := graph.FilterKnownChanIDs(preChanIDs)
require.NoError(t, err, "unable to filter chan IDs")
if !reflect.DeepEqual(preChanIDs, filteredIDs) {
t.Fatalf("chan IDs shouldn't have been filtered!")
preChanIDs := []ChannelUpdateInfo{
{ShortChannelID: scid1},
{ShortChannelID: scid2},
{ShortChannelID: scid3},
}
filteredIDs, err := graph.FilterKnownChanIDs(preChanIDs, isZombieUpdate)
require.NoError(t, err, "unable to filter chan IDs")
require.EqualValues(t, []uint64{
scid1.ToUint64(),
scid2.ToUint64(),
scid3.ToUint64(),
}, filteredIDs)
// We'll start by creating two nodes which will seed our test graph.
node1, err := createTestVertex(graph.db)
@@ -1952,7 +1970,7 @@ func TestFilterKnownChanIDs(t *testing.T) {
// Next, we'll add 5 channel ID's to the graph, each of them having a
// block height 10 blocks after the previous.
const numChans = 5
chanIDs := make([]uint64, 0, numChans)
chanIDs := make([]ChannelUpdateInfo, 0, numChans)
for i := 0; i < numChans; i++ {
channel, chanID := createEdge(
uint32(i*10), 0, 0, 0, node1, node2,
@@ -1962,11 +1980,13 @@ func TestFilterKnownChanIDs(t *testing.T) {
t.Fatalf("unable to create channel edge: %v", err)
}
chanIDs = append(chanIDs, chanID.ToUint64())
chanIDs = append(chanIDs, ChannelUpdateInfo{
ShortChannelID: chanID,
})
}
const numZombies = 5
zombieIDs := make([]uint64, 0, numZombies)
zombieIDs := make([]ChannelUpdateInfo, 0, numZombies)
for i := 0; i < numZombies; i++ {
channel, chanID := createEdge(
uint32(i*10+1), 0, 0, 0, node1, node2,
@@ -1979,13 +1999,15 @@ func TestFilterKnownChanIDs(t *testing.T) {
t.Fatalf("unable to mark edge zombie: %v", err)
}
zombieIDs = append(zombieIDs, chanID.ToUint64())
zombieIDs = append(
zombieIDs, ChannelUpdateInfo{ShortChannelID: chanID},
)
}
queryCases := []struct {
queryIDs []uint64
queryIDs []ChannelUpdateInfo
resp []uint64
resp []ChannelUpdateInfo
}{
// If we attempt to filter out all chanIDs we know of, the
// response should be the empty set.
@@ -2001,28 +2023,70 @@ func TestFilterKnownChanIDs(t *testing.T) {
// If we query for a set of ID's that we didn't insert, we
// should get the same set back.
{
queryIDs: []uint64{99, 100},
resp: []uint64{99, 100},
queryIDs: []ChannelUpdateInfo{
{ShortChannelID: lnwire.ShortChannelID{
BlockHeight: 99,
}},
{ShortChannelID: lnwire.ShortChannelID{
BlockHeight: 100,
}},
},
resp: []ChannelUpdateInfo{
{ShortChannelID: lnwire.ShortChannelID{
BlockHeight: 99,
}},
{ShortChannelID: lnwire.ShortChannelID{
BlockHeight: 100,
}},
},
},
// If we query for a super-set of our the chan ID's inserted,
// we should only get those new chanIDs back.
{
queryIDs: append(chanIDs, []uint64{99, 101}...),
resp: []uint64{99, 101},
queryIDs: append(chanIDs, []ChannelUpdateInfo{
{
ShortChannelID: lnwire.ShortChannelID{
BlockHeight: 99,
},
},
{
ShortChannelID: lnwire.ShortChannelID{
BlockHeight: 101,
},
},
}...),
resp: []ChannelUpdateInfo{
{
ShortChannelID: lnwire.ShortChannelID{
BlockHeight: 99,
},
},
{
ShortChannelID: lnwire.ShortChannelID{
BlockHeight: 101,
},
},
},
},
}
for _, queryCase := range queryCases {
resp, err := graph.FilterKnownChanIDs(queryCase.queryIDs)
if err != nil {
t.Fatalf("unable to filter chan IDs: %v", err)
resp, err := graph.FilterKnownChanIDs(
queryCase.queryIDs, isZombieUpdate,
)
require.NoError(t, err)
expectedSCIDs := make([]uint64, len(queryCase.resp))
for i, info := range queryCase.resp {
expectedSCIDs[i] = info.ShortChannelID.ToUint64()
}
if !reflect.DeepEqual(resp, queryCase.resp) {
t.Fatalf("expected %v, got %v", spew.Sdump(queryCase.resp),
spew.Sdump(resp))
if len(expectedSCIDs) == 0 {
expectedSCIDs = nil
}
require.EqualValues(t, expectedSCIDs, resp)
}
}