Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
115 changes: 95 additions & 20 deletions aliasmgr/aliasmgr.go
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,18 @@ var (
ErrAliasNotFound = fmt.Errorf("alias not found")
)

const (
// AliasFlagNone indicates standard alias behavior where the alias
// will not be added to aliasToBase after the channel is confirmed.
AliasFlagNone byte = 0x00

// AliasFlagPersistent indicates the alias should persist in the
// aliasToBase map even after the base SCID is confirmed. This is
// useful for manually added aliases that need to remain accessible
// via FindBaseSCID after 6 confirmations.
AliasFlagPersistent byte = 0x01
)

// Manager is a struct that handles aliases for LND. It has an underlying
// database that can allocate aliases for channels, stores the peer's last
// alias for use in our hop hints, and contains mappings that both the Switch
Expand Down Expand Up @@ -146,6 +158,12 @@ func (m *Manager) populateMaps() error {
// populate the Manager's actual maps.
aliasMap := make(map[lnwire.ShortChannelID]lnwire.ShortChannelID)

// This map tracks aliases that have the persistent flag set and should
// remain in aliasToBase even after confirmation.
persistentAliasMap := make(
map[lnwire.ShortChannelID]lnwire.ShortChannelID,
)

// This map caches the ChannelID/alias SCIDs stored in the database and
// is used to populate the Manager's cache.
peerAliasMap := make(map[lnwire.ChannelID]lnwire.ShortChannelID)
Expand Down Expand Up @@ -177,14 +195,23 @@ func (m *Manager) populateMaps() error {

err = aliasToBaseBucket.ForEach(func(k, v []byte) error {
// The key will be the alias SCID and the value will be
// the base SCID.
// the base SCID (8 bytes) optionally followed by flags
// (1 byte).
aliasScid := lnwire.NewShortChanIDFromInt(
byteOrder.Uint64(k),
)
baseScid := lnwire.NewShortChanIDFromInt(
byteOrder.Uint64(v),
byteOrder.Uint64(v[:8]),
)
aliasMap[aliasScid] = baseScid

// Check if the persistent flag is set. Backward
// compatible: old entries have len(v) == 8, new entries
// have len(v) == 9.
if len(v) > 8 && (v[8]&AliasFlagPersistent) != 0 {
persistentAliasMap[aliasScid] = baseScid
}

return nil
})
if err != nil {
Expand Down Expand Up @@ -214,6 +241,9 @@ func (m *Manager) populateMaps() error {
}, func() {
baseConfMap = make(map[lnwire.ShortChannelID]struct{})
aliasMap = make(map[lnwire.ShortChannelID]lnwire.ShortChannelID)
persistentAliasMap = make(
map[lnwire.ShortChannelID]lnwire.ShortChannelID,
)
peerAliasMap = make(map[lnwire.ChannelID]lnwire.ShortChannelID)
})
if err != nil {
Expand All @@ -233,6 +263,13 @@ func (m *Manager) populateMaps() error {
m.aliasToBase[aliasSCID] = baseSCID
}

// Add persistent aliases to aliasToBase even if they're confirmed.
// This allows FindBaseSCID to work for manually-added aliases that
// should survive confirmation.
for aliasSCID, baseSCID := range persistentAliasMap {
m.aliasToBase[aliasSCID] = baseSCID
}

// Populate the peer alias cache.
m.peerAlias = peerAliasMap

Expand All @@ -252,7 +289,8 @@ type addAliasCfg struct {
type AddLocalAliasOption func(cfg *addAliasCfg)

// WithBaseLookup is a functional option that controls whether a reverse lookup
// will be stored from the alias to the base scid.
// will be stored from the alias to the base scid. This reverse lookup is
// persisted and will not be wiped when the channel is confirmed.
func WithBaseLookup() AddLocalAliasOption {
return func(cfg *addAliasCfg) {
cfg.baseLookup = true
Expand All @@ -268,7 +306,8 @@ func WithBaseLookup() AddLocalAliasOption {
//
// NOTE: The following aliases will not be persisted (will be lost on restart):
// - Aliases that were created without gossip flag.
// - Aliases that correspond to confirmed channels.
// - Aliases that correspond to confirmed channels (unless WithBaseLookup
// option is used).
func (m *Manager) AddLocalAlias(alias, baseScid lnwire.ShortChannelID,
gossip, linkUpdate bool, opts ...AddLocalAliasOption) error {

Expand Down Expand Up @@ -315,14 +354,25 @@ func (m *Manager) AddLocalAlias(alias, baseScid lnwire.ShortChannelID,
return err
}

var (
aliasBytes [8]byte
baseBytes [8]byte
)

var aliasBytes [8]byte
byteOrder.PutUint64(aliasBytes[:], alias.ToUint64())
byteOrder.PutUint64(baseBytes[:], baseScid.ToUint64())
return aliasToBaseBucket.Put(aliasBytes[:], baseBytes[:])

// Write base SCID (8 bytes) + flags (1 byte).
// Always write 9 bytes for consistency and future
// extensibility.
var valueBytes [9]byte
byteOrder.PutUint64(valueBytes[:8], baseScid.ToUint64())

// Set the persistent flag if baseLookup is requested.
// The baseLookup option indicates this is a manually-added
// alias that should persist even after confirmation.
if cfg.baseLookup {
valueBytes[8] = AliasFlagPersistent
} else {
valueBytes[8] = AliasFlagNone
}

return aliasToBaseBucket.Put(aliasBytes[:], valueBytes[:])
}, func() {})
if err != nil {
return err
Expand Down Expand Up @@ -404,20 +454,45 @@ func (m *Manager) DeleteSixConfs(baseScid lnwire.ShortChannelID) error {

var baseBytes [8]byte
byteOrder.PutUint64(baseBytes[:], baseScid.ToUint64())
return baseConfBucket.Put(baseBytes[:], []byte{})
err = baseConfBucket.Put(baseBytes[:], []byte{})
if err != nil {
return err
}

// Now we'll iterate over the alias bucket and delete all of
// the aliases that do not have the persistency flag set.
aliasToBaseBucket, err := tx.CreateTopLevelBucket(aliasBucket)
if err != nil {
return err
}

return aliasToBaseBucket.ForEach(func(k, v []byte) error {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Rather than iterate over this entire bucket, couldn't we do a random read here?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Wdym by random read? We need to check all entries here and see which of the aliases correspond to the confirmed base scid.

While I was reading this comment I realized we were iterating twice over this set. So with the new commit I do everything in a single pass. PTAL

// Check if this entry maps to our baseScid.
entryBase := lnwire.NewShortChanIDFromInt(
byteOrder.Uint64(v[:8]),
)
if entryBase.ToUint64() != baseScid.ToUint64() {
return nil
}

// Check whether the persistency flag is set.
persist := len(v) > 8 && (v[8]&AliasFlagPersistent) != 0

aliasScid := lnwire.NewShortChanIDFromInt(
byteOrder.Uint64(k),
)

if !persist {
delete(m.aliasToBase, aliasScid)
}

return nil
})
}, func() {})
if err != nil {
return err
}

// Now that the database state has been updated, we'll delete all of
// the aliasToBase mappings for this SCID.
for alias, base := range m.aliasToBase {
if base.ToUint64() == baseScid.ToUint64() {
delete(m.aliasToBase, alias)
}
}

return nil
}

Expand Down
Loading
Loading