mirror of
https://github.com/lightningnetwork/lnd.git
synced 2024-11-19 09:53:54 +01:00
channeldb+routing: refactor DeleteChannelEdge to use ChannelID
In this commit, we refactor DeleteChannelEdge to use ChannelIDs rather than ChannelPoints. We do this as the only use of DeleteChannelEdge is when we are pruning zombie channels from our graph. When running under a light client, we are unable to obtain the ChannelPoint of each edge due to the expensive operations required to do so. As a stop-gap, we'll resort towards using an edge's ChannelID instead, which is already gossiped between nodes.
This commit is contained in:
parent
760f38736e
commit
0b0a9f4172
@ -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,
|
||||
)
|
||||
}
|
||||
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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
|
||||
|
Loading…
Reference in New Issue
Block a user