channeldb: add PutClosedScid and IsClosedScid

This commit adds the ability to store closed channels by scid in
the database. This will allow the gossiper to ignore channel
announcements for closed channels without having to do any
expensive validation.
This commit is contained in:
Eugene Siegel 2024-08-14 13:56:31 -04:00
parent 8939a217c3
commit 199e83d3f2
No known key found for this signature in database
GPG Key ID: 118759E83439A9B1
3 changed files with 85 additions and 0 deletions

View File

@ -43,6 +43,10 @@ var (
// created.
ErrMetaNotFound = fmt.Errorf("unable to locate meta information")
// ErrClosedScidsNotFound is returned when the closed scid bucket
// hasn't been created.
ErrClosedScidsNotFound = fmt.Errorf("closed scid bucket doesn't exist")
// ErrGraphNotFound is returned when at least one of the components of
// graph doesn't exist.
ErrGraphNotFound = fmt.Errorf("graph bucket not initialized")

View File

@ -153,6 +153,14 @@ var (
// case we'll remove all entries from the prune log with a block height
// that no longer exists.
pruneLogBucket = []byte("prune-log")
// closedScidBucket is a top-level bucket that stores scids for
// channels that we know to be closed. This is used so that we don't
// need to perform expensive validation checks if we receive a channel
// announcement for the channel again.
//
// maps: scid -> []byte{}
closedScidBucket = []byte("closed-scid")
)
const (
@ -318,6 +326,7 @@ var graphTopLevelBuckets = [][]byte{
nodeBucket,
edgeBucket,
graphMetaBucket,
closedScidBucket,
}
// Wipe completely deletes all saved state within all used buckets within the
@ -3884,6 +3893,53 @@ func (c *ChannelGraph) NumZombies() (uint64, error) {
return numZombies, nil
}
// PutClosedScid stores a SCID for a closed channel in the database. This is so
// that we can ignore channel announcements that we know to be closed without
// having to validate them and fetch a block.
func (c *ChannelGraph) PutClosedScid(scid lnwire.ShortChannelID) error {
return kvdb.Update(c.db, func(tx kvdb.RwTx) error {
closedScids, err := tx.CreateTopLevelBucket(closedScidBucket)
if err != nil {
return err
}
var k [8]byte
byteOrder.PutUint64(k[:], scid.ToUint64())
return closedScids.Put(k[:], []byte{})
}, func() {})
}
// IsClosedScid checks whether a channel identified by the passed in scid is
// closed. This helps avoid having to perform expensive validation checks.
// TODO: Add an LRU cache to cut down on disc reads.
func (c *ChannelGraph) IsClosedScid(scid lnwire.ShortChannelID) (bool, error) {
var isClosed bool
err := kvdb.View(c.db, func(tx kvdb.RTx) error {
closedScids := tx.ReadBucket(closedScidBucket)
if closedScids == nil {
return ErrClosedScidsNotFound
}
var k [8]byte
byteOrder.PutUint64(k[:], scid.ToUint64())
if closedScids.Get(k[:]) != nil {
isClosed = true
return nil
}
return nil
}, func() {
isClosed = false
})
if err != nil {
return false, err
}
return isClosed, nil
}
func putLightningNode(nodeBucket kvdb.RwBucket, aliasBucket kvdb.RwBucket, // nolint:dupl
updateIndex kvdb.RwBucket, node *LightningNode) error {

View File

@ -4037,3 +4037,28 @@ func TestGraphLoading(t *testing.T) {
graphReloaded.graphCache.nodeFeatures,
)
}
// TestClosedScid tests that we can correctly insert a SCID into the index of
// closed short channel ids.
func TestClosedScid(t *testing.T) {
t.Parallel()
graph, err := MakeTestGraph(t)
require.Nil(t, err)
scid := lnwire.ShortChannelID{}
// The scid should not exist in the closedScidBucket.
exists, err := graph.IsClosedScid(scid)
require.Nil(t, err)
require.False(t, exists)
// After we call PutClosedScid, the call to IsClosedScid should return
// true.
err = graph.PutClosedScid(scid)
require.Nil(t, err)
exists, err = graph.IsClosedScid(scid)
require.Nil(t, err)
require.True(t, exists)
}