diff --git a/channeldb/graph.go b/channeldb/graph.go index 023df070..eaf3503c 100644 --- a/channeldb/graph.go +++ b/channeldb/graph.go @@ -810,7 +810,7 @@ func (c *ChannelGraph) PruneGraph(spentOutputs []*wire.OutPoint, var opBytes bytes.Buffer if err := writeOutpoint(&opBytes, chanPoint); err != nil { - return nil + return err } // First attempt to see if the channel exists within @@ -832,9 +832,9 @@ func (c *ChannelGraph) PruneGraph(spentOutputs []*wire.OutPoint, // will be returned if that outpoint isn't known to be // a channel. If no error is returned, then a channel // was successfully pruned. - err = delChannelByEdge( + err = delChannelEdge( edges, edgeIndex, chanIndex, zombieIndex, nodes, - chanPoint, false, + chanID, false, ) if err != nil && err != ErrEdgeNotFound { return err @@ -1070,9 +1070,9 @@ func (c *ChannelGraph) DisconnectBlockAtHeight(height uint32) ([]*ChannelEdgeInf if err != nil { return err } - err = delChannelByEdge( + err = delChannelEdge( edges, edgeIndex, chanIndex, zombieIndex, nodes, - &edgeInfo.ChannelPoint, false, + k, false, ) if err != nil && err != ErrEdgeNotFound { return err @@ -1163,11 +1163,11 @@ func (c *ChannelGraph) PruneTip() (*chainhash.Hash, uint32, error) { return &tipHash, tipHeight, nil } -// DeleteChannelEdge removes an edge from the database as identified by its -// funding outpoint and also marks it as a zombie. This ensures that we're -// unable to re-add this to our database once again. If the edge does not exist -// within the database, then ErrEdgeNotFound will be returned. -func (c *ChannelGraph) DeleteChannelEdge(chanPoint *wire.OutPoint) error { +// DeleteChannelEdges removes edges with the given channel IDs from the database +// and marks them as zombies. This ensures that we're unable to re-add it to our +// database once again. If an edge does not exist within the database, then +// ErrEdgeNotFound will be returned. +func (c *ChannelGraph) DeleteChannelEdges(chanIDs ...uint64) error { // TODO(roasbeef): possibly delete from node bucket if node has no more // channels // TODO(roasbeef): don't delete both edges? @@ -1175,23 +1175,11 @@ func (c *ChannelGraph) DeleteChannelEdge(chanPoint *wire.OutPoint) error { c.cacheMu.Lock() defer c.cacheMu.Unlock() - var chanID uint64 err := c.db.Update(func(tx *bbolt.Tx) error { - var err error - chanID, err = getChanID(tx, chanPoint) - if err != nil { - return err - } - - // First grab the edges bucket which houses the information - // we'd like to delete edges := tx.Bucket(edgeBucket) if edges == nil { return ErrEdgeNotFound } - - // Next grab the two edge indexes which will also need to be - // updated. edgeIndex := edges.Bucket(edgeIndexBucket) if edgeIndex == nil { return ErrEdgeNotFound @@ -1209,17 +1197,28 @@ func (c *ChannelGraph) DeleteChannelEdge(chanPoint *wire.OutPoint) error { return err } - return delChannelByEdge( - edges, edgeIndex, chanIndex, zombieIndex, nodes, - chanPoint, true, - ) + var rawChanID [8]byte + for _, chanID := range chanIDs { + byteOrder.PutUint64(rawChanID[:], chanID) + err := delChannelEdge( + edges, edgeIndex, chanIndex, zombieIndex, nodes, + rawChanID[:], true, + ) + if err != nil { + return err + } + } + + return nil }) if err != nil { return err } - c.rejectCache.remove(chanID) - c.chanCache.remove(chanID) + for _, chanID := range chanIDs { + c.rejectCache.remove(chanID) + c.chanCache.remove(chanID) + } return nil } @@ -1244,7 +1243,7 @@ func (c *ChannelGraph) ChannelID(chanPoint *wire.OutPoint) (uint64, error) { func getChanID(tx *bbolt.Tx, chanPoint *wire.OutPoint) (uint64, error) { var b bytes.Buffer if err := writeOutpoint(&b, chanPoint); err != nil { - return 0, nil + return 0, err } edges := tx.Bucket(edgeBucket) @@ -1742,30 +1741,14 @@ func delEdgeUpdateIndexEntry(edgesBucket *bbolt.Bucket, chanID uint64, return nil } -func delChannelByEdge(edges, edgeIndex, chanIndex, zombieIndex, - nodes *bbolt.Bucket, chanPoint *wire.OutPoint, isZombie bool) error { +func delChannelEdge(edges, edgeIndex, chanIndex, zombieIndex, + nodes *bbolt.Bucket, chanID []byte, isZombie bool) error { - var b bytes.Buffer - if err := writeOutpoint(&b, chanPoint); err != nil { + edgeInfo, err := fetchChanEdgeInfo(edgeIndex, chanID) + if err != nil { return err } - // If the channel's outpoint doesn't exist within the outpoint index, - // then the edge does not exist. - chanID := chanIndex.Get(b.Bytes()) - if chanID == nil { - return ErrEdgeNotFound - } - - // Otherwise we obtain the two public keys from the mapping: chanID -> - // pubKey1 || pubKey2. With this, we can construct the keys which house - // both of the directed edges for this channel. - nodeKeys := edgeIndex.Get(chanID) - if nodeKeys == nil { - return fmt.Errorf("could not find nodekeys for chanID %v", - chanID) - } - // We'll also remove the entry in the edge update index bucket before // we delete the edges themselves so we can access their last update // times. @@ -1789,13 +1772,13 @@ func delChannelByEdge(edges, edgeIndex, chanIndex, zombieIndex, // With the latter half constructed, copy over the first public key to // delete the edge in this direction, then the second to delete the // edge in the opposite direction. - copy(edgeKey[:33], nodeKeys[:33]) + copy(edgeKey[:33], edgeInfo.NodeKey1Bytes[:]) if edges.Get(edgeKey[:]) != nil { if err := edges.Delete(edgeKey[:]); err != nil { return err } } - copy(edgeKey[:33], nodeKeys[33:]) + copy(edgeKey[:33], edgeInfo.NodeKey2Bytes[:]) if edges.Get(edgeKey[:]) != nil { if err := edges.Delete(edgeKey[:]); err != nil { return err @@ -1807,6 +1790,10 @@ func delChannelByEdge(edges, edgeIndex, chanIndex, zombieIndex, if err := edgeIndex.Delete(chanID); err != nil { return err } + var b bytes.Buffer + if err := writeOutpoint(&b, &edgeInfo.ChannelPoint); err != nil { + return err + } if err := chanIndex.Delete(b.Bytes()); err != nil { return err } @@ -1818,12 +1805,9 @@ func delChannelByEdge(edges, edgeIndex, chanIndex, zombieIndex, return nil } - var pubKey1, pubKey2 [33]byte - copy(pubKey1[:], nodeKeys[:33]) - copy(pubKey2[:], nodeKeys[33:]) - return markEdgeZombie( - zombieIndex, byteOrder.Uint64(chanID), pubKey1, pubKey2, + zombieIndex, byteOrder.Uint64(chanID), edgeInfo.NodeKey1Bytes, + edgeInfo.NodeKey2Bytes, ) } diff --git a/channeldb/graph_test.go b/channeldb/graph_test.go index e8c9440e..f3fde1d2 100644 --- a/channeldb/graph_test.go +++ b/channeldb/graph_test.go @@ -362,7 +362,7 @@ func TestEdgeInsertionDeletion(t *testing.T) { // Next, attempt to delete the edge from the database, again this // should proceed without any issues. - if err := graph.DeleteChannelEdge(&outpoint); err != nil { + if err := graph.DeleteChannelEdges(chanID); err != nil { t.Fatalf("unable to delete edge: %v", err) } @@ -381,7 +381,7 @@ func TestEdgeInsertionDeletion(t *testing.T) { // Finally, attempt to delete a (now) non-existent edge within the // database, this should result in an error. - err = graph.DeleteChannelEdge(&outpoint) + err = graph.DeleteChannelEdges(chanID) if err != ErrEdgeNotFound { t.Fatalf("deleting a non-existent edge should fail!") } @@ -1750,7 +1750,7 @@ func TestFilterKnownChanIDs(t *testing.T) { if err := graph.AddChannelEdge(&channel); err != nil { t.Fatalf("unable to create channel edge: %v", err) } - err := graph.DeleteChannelEdge(&channel.ChannelPoint) + err := graph.DeleteChannelEdges(channel.ChannelID) if err != nil { t.Fatalf("unable to mark edge zombie: %v", err) } @@ -2017,7 +2017,7 @@ func TestFetchChanInfos(t *testing.T) { if err := graph.AddChannelEdge(&zombieChan); err != nil { t.Fatalf("unable to create channel edge: %v", err) } - err = graph.DeleteChannelEdge(&zombieChan.ChannelPoint) + err = graph.DeleteChannelEdges(zombieChan.ChannelID) if err != nil { t.Fatalf("unable to delete and mark edge zombie: %v", err) } @@ -2634,7 +2634,7 @@ func TestNodeIsPublic(t *testing.T) { // graph. This will make Alice be seen as a private node as it no longer // has any advertised edges. for _, graph := range graphs { - err := graph.DeleteChannelEdge(&aliceBobEdge.ChannelPoint) + err := graph.DeleteChannelEdges(aliceBobEdge.ChannelID) if err != nil { t.Fatalf("unable to remove edge: %v", err) } @@ -2651,7 +2651,7 @@ func TestNodeIsPublic(t *testing.T) { // completely remove the edge as it is not possible for her to know of // it without it being advertised. for i, graph := range graphs { - err := graph.DeleteChannelEdge(&bobCarolEdge.ChannelPoint) + err := graph.DeleteChannelEdges(bobCarolEdge.ChannelID) if err != nil { t.Fatalf("unable to remove edge: %v", err) } @@ -2884,7 +2884,7 @@ func TestGraphZombieIndex(t *testing.T) { // If we delete the edge and mark it as a zombie, then we should expect // to see it within the index. - err = graph.DeleteChannelEdge(&edge.ChannelPoint) + err = graph.DeleteChannelEdges(edge.ChannelID) if err != nil { t.Fatalf("unable to mark edge as zombie: %v", err) } diff --git a/routing/router.go b/routing/router.go index 18607bf5..1b12925c 100644 --- a/routing/router.go +++ b/routing/router.go @@ -634,7 +634,7 @@ func (r *ChannelRouter) syncGraphWithChain() error { // usually signals that a channel has been closed on-chain. We do this // periodically to keep a healthy, lively routing table. func (r *ChannelRouter) pruneZombieChans() error { - var chansToPrune []wire.OutPoint + var chansToPrune []uint64 chanExpiry := r.cfg.ChannelPruneExpiry log.Infof("Examining channel graph for zombie channels") @@ -660,17 +660,17 @@ func (r *ChannelRouter) pruneZombieChans() error { if e1 != nil { e1Zombie = time.Since(e1.LastUpdate) >= chanExpiry if e1Zombie { - log.Tracef("Edge #1 of ChannelPoint(%v) "+ - "last update: %v", - info.ChannelPoint, e1.LastUpdate) + log.Tracef("Edge #1 of ChannelID(%v) last "+ + "update: %v", info.ChannelID, + e1.LastUpdate) } } if e2 != nil { e2Zombie = time.Since(e2.LastUpdate) >= chanExpiry if e2Zombie { - log.Tracef("Edge #2 of ChannelPoint(%v) "+ - "last update: %v", - info.ChannelPoint, e2.LastUpdate) + log.Tracef("Edge #2 of ChannelID(%v) last "+ + "update: %v", info.ChannelID, + e2.LastUpdate) } } @@ -705,11 +705,11 @@ func (r *ChannelRouter) pruneZombieChans() error { return nil } - log.Debugf("ChannelPoint(%v) is a zombie, collecting to prune", - info.ChannelPoint) + log.Debugf("ChannelID(%v) is a zombie, collecting to prune", + info.ChannelID) // TODO(roasbeef): add ability to delete single directional edge - chansToPrune = append(chansToPrune, info.ChannelPoint) + chansToPrune = append(chansToPrune, info.ChannelID) // As we're detecting this as a zombie channel, we'll add this // to the set of recently rejected items so we don't re-accept @@ -732,15 +732,11 @@ func (r *ChannelRouter) pruneZombieChans() error { // With the set of zombie-like channels obtained, we'll do another pass // to delete them from the channel graph. - for _, chanToPrune := range chansToPrune { - log.Tracef("Pruning zombie channel with ChannelPoint(%v)", - chanToPrune) - - err := r.cfg.Graph.DeleteChannelEdge(&chanToPrune) - if err != nil { - return fmt.Errorf("unable to prune zombie with "+ - "ChannelPoint(%v): %v", chanToPrune, err) - } + for _, chanID := range chansToPrune { + log.Tracef("Pruning zombie channel with ChannelID(%v)", chanID) + } + if err := r.cfg.Graph.DeleteChannelEdges(chansToPrune...); err != nil { + return fmt.Errorf("unable to delete zombie channels: %v", err) } // With the channels pruned, we'll also attempt to prune any nodes that