mirror of
https://github.com/lightningnetwork/lnd.git
synced 2025-08-02 17:52:28 +02:00
channeldb+routing: extend edge lookup methods with zombie index check
In this commit, we extend the graph's FetchChannelEdgesByID and HasChannelEdge methods to also check the zombie index whenever the edge to be looked up doesn't exist within the edge index. We do this to signal to callers that the edge is known, but only as a zombie, and the only information that we have about the edge are the node public keys of the two parties involved in the edge. In the event that an edge does exist within the zombie index, we make an additional check on edge policies to ensure they are not within the router's pruning window, indicating that it is a fresh update.
This commit is contained in:
@@ -76,7 +76,7 @@ type ChannelGraphSource interface {
|
||||
IsPublicNode(node Vertex) (bool, error)
|
||||
|
||||
// IsKnownEdge returns true if the graph source already knows of the
|
||||
// passed channel ID.
|
||||
// passed channel ID either as a live or zombie edge.
|
||||
IsKnownEdge(chanID lnwire.ShortChannelID) bool
|
||||
|
||||
// IsStaleEdgePolicy returns true if the graph source has a channel
|
||||
@@ -1009,12 +1009,19 @@ func (r *ChannelRouter) processUpdate(msg interface{}) error {
|
||||
|
||||
// Prior to processing the announcement we first check if we
|
||||
// already know of this channel, if so, then we can exit early.
|
||||
_, _, exists, err := r.cfg.Graph.HasChannelEdge(msg.ChannelID)
|
||||
_, _, exists, isZombie, err := r.cfg.Graph.HasChannelEdge(
|
||||
msg.ChannelID,
|
||||
)
|
||||
if err != nil && err != channeldb.ErrGraphNoEdgesFound {
|
||||
return errors.Errorf("unable to check for edge "+
|
||||
"existence: %v", err)
|
||||
} else if exists {
|
||||
return newErrf(ErrIgnored, "Ignoring msg for known "+
|
||||
}
|
||||
if isZombie {
|
||||
return newErrf(ErrIgnored, "ignoring msg for zombie "+
|
||||
"chan_id=%v", msg.ChannelID)
|
||||
}
|
||||
if exists {
|
||||
return newErrf(ErrIgnored, "ignoring msg for known "+
|
||||
"chan_id=%v", msg.ChannelID)
|
||||
}
|
||||
|
||||
@@ -1130,19 +1137,29 @@ func (r *ChannelRouter) processUpdate(msg interface{}) error {
|
||||
r.channelEdgeMtx.Lock(msg.ChannelID)
|
||||
defer r.channelEdgeMtx.Unlock(msg.ChannelID)
|
||||
|
||||
edge1Timestamp, edge2Timestamp, exists, err := r.cfg.Graph.HasChannelEdge(
|
||||
msg.ChannelID,
|
||||
)
|
||||
edge1Timestamp, edge2Timestamp, exists, isZombie, err :=
|
||||
r.cfg.Graph.HasChannelEdge(msg.ChannelID)
|
||||
if err != nil && err != channeldb.ErrGraphNoEdgesFound {
|
||||
return errors.Errorf("unable to check for edge "+
|
||||
"existence: %v", err)
|
||||
|
||||
}
|
||||
|
||||
// If the channel is marked as a zombie in our database, and
|
||||
// we consider this a stale update, then we should not apply the
|
||||
// policy.
|
||||
isStaleUpdate := time.Since(msg.LastUpdate) > r.cfg.ChannelPruneExpiry
|
||||
if isZombie && isStaleUpdate {
|
||||
return newErrf(ErrIgnored, "ignoring stale update "+
|
||||
"(flags=%v|%v) for zombie chan_id=%v",
|
||||
msg.MessageFlags, msg.ChannelFlags,
|
||||
msg.ChannelID)
|
||||
}
|
||||
|
||||
// If the channel doesn't exist in our database, we cannot
|
||||
// apply the updated policy.
|
||||
if !exists {
|
||||
return newErrf(ErrIgnored, "Ignoring update "+
|
||||
return newErrf(ErrIgnored, "ignoring update "+
|
||||
"(flags=%v|%v) for unknown chan_id=%v",
|
||||
msg.MessageFlags, msg.ChannelFlags,
|
||||
msg.ChannelID)
|
||||
@@ -2241,12 +2258,12 @@ func (r *ChannelRouter) IsPublicNode(node Vertex) (bool, error) {
|
||||
}
|
||||
|
||||
// IsKnownEdge returns true if the graph source already knows of the passed
|
||||
// channel ID.
|
||||
// channel ID either as a live or zombie edge.
|
||||
//
|
||||
// NOTE: This method is part of the ChannelGraphSource interface.
|
||||
func (r *ChannelRouter) IsKnownEdge(chanID lnwire.ShortChannelID) bool {
|
||||
_, _, exists, _ := r.cfg.Graph.HasChannelEdge(chanID.ToUint64())
|
||||
return exists
|
||||
_, _, exists, isZombie, _ := r.cfg.Graph.HasChannelEdge(chanID.ToUint64())
|
||||
return exists || isZombie
|
||||
}
|
||||
|
||||
// IsStaleEdgePolicy returns true if the graph soruce has a channel edge for
|
||||
@@ -2256,14 +2273,19 @@ func (r *ChannelRouter) IsKnownEdge(chanID lnwire.ShortChannelID) bool {
|
||||
func (r *ChannelRouter) IsStaleEdgePolicy(chanID lnwire.ShortChannelID,
|
||||
timestamp time.Time, flags lnwire.ChanUpdateChanFlags) bool {
|
||||
|
||||
edge1Timestamp, edge2Timestamp, exists, err := r.cfg.Graph.HasChannelEdge(
|
||||
chanID.ToUint64(),
|
||||
)
|
||||
edge1Timestamp, edge2Timestamp, exists, isZombie, err :=
|
||||
r.cfg.Graph.HasChannelEdge(chanID.ToUint64())
|
||||
if err != nil {
|
||||
return false
|
||||
|
||||
}
|
||||
|
||||
// If we know of the edge as a zombie, then we'll check the timestamp of
|
||||
// this message to determine whether it's fresh.
|
||||
if isZombie {
|
||||
return time.Since(timestamp) > r.cfg.ChannelPruneExpiry
|
||||
}
|
||||
|
||||
// If we don't know of the edge, then it means it's fresh (thus not
|
||||
// stale).
|
||||
if !exists {
|
||||
@@ -2275,7 +2297,6 @@ func (r *ChannelRouter) IsStaleEdgePolicy(chanID lnwire.ShortChannelID,
|
||||
// already have the most up to date information for that edge. If so,
|
||||
// then we can exit early.
|
||||
switch {
|
||||
|
||||
// A flag set of 0 indicates this is an announcement for the "first"
|
||||
// node in the channel.
|
||||
case flags&lnwire.ChanUpdateDirection == 0:
|
||||
|
@@ -1549,21 +1549,27 @@ func TestWakeUpOnStaleBranch(t *testing.T) {
|
||||
}
|
||||
|
||||
// Check that the fundingTxs are in the graph db.
|
||||
_, _, has, err := ctx.graph.HasChannelEdge(chanID1)
|
||||
_, _, has, isZombie, err := ctx.graph.HasChannelEdge(chanID1)
|
||||
if err != nil {
|
||||
t.Fatalf("error looking for edge: %v", chanID1)
|
||||
}
|
||||
if !has {
|
||||
t.Fatalf("could not find edge in graph")
|
||||
}
|
||||
if isZombie {
|
||||
t.Fatal("edge was marked as zombie")
|
||||
}
|
||||
|
||||
_, _, has, err = ctx.graph.HasChannelEdge(chanID2)
|
||||
_, _, has, isZombie, err = ctx.graph.HasChannelEdge(chanID2)
|
||||
if err != nil {
|
||||
t.Fatalf("error looking for edge: %v", chanID2)
|
||||
}
|
||||
if !has {
|
||||
t.Fatalf("could not find edge in graph")
|
||||
}
|
||||
if isZombie {
|
||||
t.Fatal("edge was marked as zombie")
|
||||
}
|
||||
|
||||
// Stop the router, so we can reorg the chain while its offline.
|
||||
if err := ctx.router.Stop(); err != nil {
|
||||
@@ -1607,22 +1613,27 @@ func TestWakeUpOnStaleBranch(t *testing.T) {
|
||||
// The channel with chanID2 should not be in the database anymore,
|
||||
// since it is not confirmed on the longest chain. chanID1 should
|
||||
// still be.
|
||||
_, _, has, err = ctx.graph.HasChannelEdge(chanID1)
|
||||
_, _, has, isZombie, err = ctx.graph.HasChannelEdge(chanID1)
|
||||
if err != nil {
|
||||
t.Fatalf("error looking for edge: %v", chanID1)
|
||||
}
|
||||
if !has {
|
||||
t.Fatalf("did not find edge in graph")
|
||||
}
|
||||
if isZombie {
|
||||
t.Fatal("edge was marked as zombie")
|
||||
}
|
||||
|
||||
_, _, has, err = ctx.graph.HasChannelEdge(chanID2)
|
||||
_, _, has, isZombie, err = ctx.graph.HasChannelEdge(chanID2)
|
||||
if err != nil {
|
||||
t.Fatalf("error looking for edge: %v", chanID2)
|
||||
}
|
||||
if has {
|
||||
t.Fatalf("found edge in graph")
|
||||
}
|
||||
|
||||
if isZombie {
|
||||
t.Fatal("reorged edge should not be marked as zombie")
|
||||
}
|
||||
}
|
||||
|
||||
// TestDisconnectedBlocks checks that the router handles a reorg happening when
|
||||
@@ -1755,21 +1766,27 @@ func TestDisconnectedBlocks(t *testing.T) {
|
||||
}
|
||||
|
||||
// Check that the fundingTxs are in the graph db.
|
||||
_, _, has, err := ctx.graph.HasChannelEdge(chanID1)
|
||||
_, _, has, isZombie, err := ctx.graph.HasChannelEdge(chanID1)
|
||||
if err != nil {
|
||||
t.Fatalf("error looking for edge: %v", chanID1)
|
||||
}
|
||||
if !has {
|
||||
t.Fatalf("could not find edge in graph")
|
||||
}
|
||||
if isZombie {
|
||||
t.Fatal("edge was marked as zombie")
|
||||
}
|
||||
|
||||
_, _, has, err = ctx.graph.HasChannelEdge(chanID2)
|
||||
_, _, has, isZombie, err = ctx.graph.HasChannelEdge(chanID2)
|
||||
if err != nil {
|
||||
t.Fatalf("error looking for edge: %v", chanID2)
|
||||
}
|
||||
if !has {
|
||||
t.Fatalf("could not find edge in graph")
|
||||
}
|
||||
if isZombie {
|
||||
t.Fatal("edge was marked as zombie")
|
||||
}
|
||||
|
||||
// Create a 15 block fork. We first let the chainView notify the router
|
||||
// about stale blocks, before sending the now connected blocks. We do
|
||||
@@ -1796,22 +1813,27 @@ func TestDisconnectedBlocks(t *testing.T) {
|
||||
|
||||
// chanID2 should not be in the database anymore, since it is not
|
||||
// confirmed on the longest chain. chanID1 should still be.
|
||||
_, _, has, err = ctx.graph.HasChannelEdge(chanID1)
|
||||
_, _, has, isZombie, err = ctx.graph.HasChannelEdge(chanID1)
|
||||
if err != nil {
|
||||
t.Fatalf("error looking for edge: %v", chanID1)
|
||||
}
|
||||
if !has {
|
||||
t.Fatalf("did not find edge in graph")
|
||||
}
|
||||
if isZombie {
|
||||
t.Fatal("edge was marked as zombie")
|
||||
}
|
||||
|
||||
_, _, has, err = ctx.graph.HasChannelEdge(chanID2)
|
||||
_, _, has, isZombie, err = ctx.graph.HasChannelEdge(chanID2)
|
||||
if err != nil {
|
||||
t.Fatalf("error looking for edge: %v", chanID2)
|
||||
}
|
||||
if has {
|
||||
t.Fatalf("found edge in graph")
|
||||
}
|
||||
|
||||
if isZombie {
|
||||
t.Fatal("reorged edge should not be marked as zombie")
|
||||
}
|
||||
}
|
||||
|
||||
// TestChansClosedOfflinePruneGraph tests that if channels we know of are
|
||||
@@ -1876,13 +1898,16 @@ func TestRouterChansClosedOfflinePruneGraph(t *testing.T) {
|
||||
}
|
||||
|
||||
// The router should now be aware of the channel we created above.
|
||||
_, _, hasChan, err := ctx.graph.HasChannelEdge(chanID1.ToUint64())
|
||||
_, _, hasChan, isZombie, err := ctx.graph.HasChannelEdge(chanID1.ToUint64())
|
||||
if err != nil {
|
||||
t.Fatalf("error looking for edge: %v", chanID1)
|
||||
}
|
||||
if !hasChan {
|
||||
t.Fatalf("could not find edge in graph")
|
||||
}
|
||||
if isZombie {
|
||||
t.Fatal("edge was marked as zombie")
|
||||
}
|
||||
|
||||
// With the transaction included, and the router's database state
|
||||
// updated, we'll now mine 5 additional blocks on top of it.
|
||||
@@ -1957,13 +1982,16 @@ func TestRouterChansClosedOfflinePruneGraph(t *testing.T) {
|
||||
|
||||
// At this point, the channel that was pruned should no longer be known
|
||||
// by the router.
|
||||
_, _, hasChan, err = ctx.graph.HasChannelEdge(chanID1.ToUint64())
|
||||
_, _, hasChan, isZombie, err = ctx.graph.HasChannelEdge(chanID1.ToUint64())
|
||||
if err != nil {
|
||||
t.Fatalf("error looking for edge: %v", chanID1)
|
||||
}
|
||||
if hasChan {
|
||||
t.Fatalf("channel was found in graph but shouldn't have been")
|
||||
}
|
||||
if isZombie {
|
||||
t.Fatal("closed channel should not be marked as zombie")
|
||||
}
|
||||
}
|
||||
|
||||
// TestFindPathFeeWeighting tests that the findPath method will properly prefer
|
||||
|
Reference in New Issue
Block a user