channeldb: ensure that when we delete a channel we delete entry in edge update index

In this commit, we ensure that all indexes for a particular channel have
any relevant keys deleted once a channel is removed from the database.
Before this commit, if we pruned a channel due to closing, then its
entry in the channel update index would ever be removed.
This commit is contained in:
Olaoluwa Osuntokun 2018-04-27 16:21:46 -07:00
parent 55dfc17c05
commit 70dffe7e99
No known key found for this signature in database
GPG Key ID: 964EA263DD637C21

@ -586,6 +586,10 @@ func (c *ChannelGraph) PruneGraph(spentOutputs []*wire.OutPoint,
if err != nil {
return err
}
nodes, err := tx.CreateBucketIfNotExists(nodeBucket)
if err != nil {
return err
}
// For each of the outpoints that have been spent within the
// block, we attempt to delete them from the graph as if that
@ -619,8 +623,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(edges, edgeIndex, chanIndex,
chanPoint)
err = delChannelByEdge(
edges, edgeIndex, chanIndex, nodes, chanPoint,
)
if err != nil && err != ErrEdgeNotFound {
return err
}
@ -690,16 +695,18 @@ func (c *ChannelGraph) DisconnectBlockAtHeight(height uint32) ([]*ChannelEdgeInf
if err != nil {
return err
}
edgeIndex, err := edges.CreateBucketIfNotExists(edgeIndexBucket)
if err != nil {
return err
}
chanIndex, err := edges.CreateBucketIfNotExists(channelPointBucket)
if err != nil {
return err
}
nodes, err := tx.CreateBucketIfNotExists(nodeBucket)
if err != nil {
return err
}
// Scan from chanIDStart to chanIDEnd, deleting every
// found edge.
@ -713,7 +720,7 @@ func (c *ChannelGraph) DisconnectBlockAtHeight(height uint32) ([]*ChannelEdgeInf
return err
}
err = delChannelByEdge(
edges, edgeIndex, chanIndex, &edgeInfo.ChannelPoint,
edges, edgeIndex, chanIndex, nodes, &edgeInfo.ChannelPoint,
)
if err != nil && err != ErrEdgeNotFound {
return err
@ -823,8 +830,12 @@ func (c *ChannelGraph) DeleteChannelEdge(chanPoint *wire.OutPoint) error {
if err != nil {
return err
}
nodes, err := tx.CreateBucketIfNotExists(nodeBucket)
if err != nil {
return err
}
return delChannelByEdge(edges, edgeIndex, chanIndex, chanPoint)
return delChannelByEdge(edges, edgeIndex, chanIndex, nodes, chanPoint)
})
}
@ -1236,38 +1247,76 @@ func (c *ChannelGraph) FetchChanInfos(chanIDs []uint64) ([]ChannelEdge, error) {
return chanEdges, nil
}
func delEdgeUpdateIndexEntry(edgesBucket *bolt.Bucket, chanID uint64,
edge1, edge2 *ChannelEdgePolicy) error {
// First, we'll fetch the edge update index bucket which currently
// stores an entry for the channel we're about to delete.
updateIndex, err := edgesBucket.CreateBucketIfNotExists(
edgeUpdateIndexBucket,
)
if err != nil {
return err
}
// Now that we have the bucket, we'll attempt to construct a template
// for the index key: updateTime || chanid.
var indexKey [8 + 8]byte
byteOrder.PutUint64(indexKey[8:], chanID)
// With the template constructed, we'll attempt to delete an entry that
// would have been created by both edges: we'll alternate the update
// times, as one may had overridden the other.
if edge1 != nil {
byteOrder.PutUint64(indexKey[:8], uint64(edge1.LastUpdate.Unix()))
if err := updateIndex.Delete(indexKey[:]); err != nil {
return err
}
}
// We'll also attempt to delete the entry that may have been created by
// the second edge.
if edge2 != nil {
byteOrder.PutUint64(indexKey[:8], uint64(edge2.LastUpdate.Unix()))
if err := updateIndex.Delete(indexKey[:]); err != nil {
return err
}
}
return nil
}
func delChannelByEdge(edges *bolt.Bucket, edgeIndex *bolt.Bucket,
chanIndex *bolt.Bucket, chanPoint *wire.OutPoint) error {
chanIndex *bolt.Bucket, nodes *bolt.Bucket, chanPoint *wire.OutPoint) error {
var b bytes.Buffer
if err := writeOutpoint(&b, chanPoint); err != nil {
return err
}
// If the channel's outpoint doesn't exist within the outpoint
// index, then the edge does not exist.
// 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.
// 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)
}
// The edge key is of the format pubKey || chanID. First we
// construct the latter half, populating the channel ID.
// The edge key is of the format pubKey || chanID. First we construct
// the latter half, populating the channel ID.
var edgeKey [33 + 8]byte
copy(edgeKey[33:], chanID)
// 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.
// 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])
if edges.Get(edgeKey[:]) != nil {
if err := edges.Delete(edgeKey[:]); err != nil {
@ -1281,8 +1330,21 @@ func delChannelByEdge(edges *bolt.Bucket, edgeIndex *bolt.Bucket,
}
}
// Finally, with the edge data deleted, we can purge the
// information from the two edge indexes.
// We'll also remove the entry in the edge update index bucket.
cid := byteOrder.Uint64(chanID)
edge1, edge2, err := fetchChanEdgePolicies(
edgeIndex, edges, nodes, chanID, nil,
)
if err != nil {
return err
}
err = delEdgeUpdateIndexEntry(edges, cid, edge1, edge2)
if err != nil {
return err
}
// Finally, with the edge data deleted, we can purge the information
// from the two edge indexes.
if err := edgeIndex.Delete(chanID); err != nil {
return err
}