channeldb: avoid modifying bucket during cursor traversal

This is not safe according to bbolt documentation.
This commit is contained in:
Johan T. Halseth 2019-06-12 14:50:59 +02:00
parent ed8d635cf1
commit f98f452528
No known key found for this signature in database
GPG Key ID: 15BAADA29DA20D26
2 changed files with 18 additions and 20 deletions

@ -2087,10 +2087,6 @@ func (c *OpenChannel) CloseChannel(summary *ChannelCloseSummary) error {
// information stored within the revocation log. // information stored within the revocation log.
logBucket := chanBucket.Bucket(revocationLogBucket) logBucket := chanBucket.Bucket(revocationLogBucket)
if logBucket != nil { if logBucket != nil {
err := wipeChannelLogEntries(logBucket)
if err != nil {
return err
}
err = chanBucket.DeleteBucket(revocationLogBucket) err = chanBucket.DeleteBucket(revocationLogBucket)
if err != nil { if err != nil {
return err return err
@ -2713,16 +2709,3 @@ func fetchChannelLogEntry(log *bbolt.Bucket,
commitReader := bytes.NewReader(commitBytes) commitReader := bytes.NewReader(commitBytes)
return deserializeChanCommit(commitReader) return deserializeChanCommit(commitReader)
} }
func wipeChannelLogEntries(log *bbolt.Bucket) error {
// TODO(roasbeef): comment
logCursor := log.Cursor()
for k, _ := logCursor.First(); k != nil; k, _ = logCursor.Next() {
if err := logCursor.Delete(); err != nil {
return err
}
}
return nil
}

@ -1061,6 +1061,9 @@ func (c *ChannelGraph) DisconnectBlockAtHeight(height uint32) ([]*ChannelEdgeInf
// Scan from chanIDStart to chanIDEnd, deleting every // Scan from chanIDStart to chanIDEnd, deleting every
// found edge. // found edge.
// NOTE: we must delete the edges after the cursor loop, since
// modifying the bucket while traversing is not safe.
var keys [][]byte
cursor := edgeIndex.Cursor() cursor := edgeIndex.Cursor()
for k, v := cursor.Seek(chanIDStart[:]); k != nil && for k, v := cursor.Seek(chanIDStart[:]); k != nil &&
bytes.Compare(k, chanIDEnd[:]) <= 0; k, v = cursor.Next() { bytes.Compare(k, chanIDEnd[:]) <= 0; k, v = cursor.Next() {
@ -1070,6 +1073,12 @@ func (c *ChannelGraph) DisconnectBlockAtHeight(height uint32) ([]*ChannelEdgeInf
if err != nil { if err != nil {
return err return err
} }
keys = append(keys, k)
removedChans = append(removedChans, &edgeInfo)
}
for _, k := range keys {
err = delChannelEdge( err = delChannelEdge(
edges, edgeIndex, chanIndex, zombieIndex, nodes, edges, edgeIndex, chanIndex, zombieIndex, nodes,
k, false, k, false,
@ -1077,8 +1086,6 @@ func (c *ChannelGraph) DisconnectBlockAtHeight(height uint32) ([]*ChannelEdgeInf
if err != nil && err != ErrEdgeNotFound { if err != nil && err != ErrEdgeNotFound {
return err return err
} }
removedChans = append(removedChans, &edgeInfo)
} }
// Delete all the entries in the prune log having a height // Delete all the entries in the prune log having a height
@ -1099,10 +1106,18 @@ func (c *ChannelGraph) DisconnectBlockAtHeight(height uint32) ([]*ChannelEdgeInf
var pruneKeyEnd [4]byte var pruneKeyEnd [4]byte
byteOrder.PutUint32(pruneKeyEnd[:], math.MaxUint32) byteOrder.PutUint32(pruneKeyEnd[:], math.MaxUint32)
// To avoid modifying the bucket while traversing, we delete
// the keys in a second loop.
var pruneKeys [][]byte
pruneCursor := pruneBucket.Cursor() pruneCursor := pruneBucket.Cursor()
for k, _ := pruneCursor.Seek(pruneKeyStart[:]); k != nil && for k, _ := pruneCursor.Seek(pruneKeyStart[:]); k != nil &&
bytes.Compare(k, pruneKeyEnd[:]) <= 0; k, _ = pruneCursor.Next() { bytes.Compare(k, pruneKeyEnd[:]) <= 0; k, _ = pruneCursor.Next() {
if err := pruneCursor.Delete(); err != nil {
pruneKeys = append(pruneKeys, k)
}
for _, k := range pruneKeys {
if err := pruneBucket.Delete(k); err != nil {
return err return err
} }
} }