8787 ErrAliasNotFound = fmt .Errorf ("alias not found" )
8888)
8989
90+ const (
91+ // AliasFlagNone indicates standard alias behavior where the alias
92+ // will not be added to aliasToBase after the channel is confirmed.
93+ AliasFlagNone byte = 0x00
94+
95+ // AliasFlagPersistent indicates the alias should persist in the
96+ // aliasToBase map even after the base SCID is confirmed. This is
97+ // useful for manually added aliases that need to remain accessible
98+ // via FindBaseSCID after 6 confirmations.
99+ AliasFlagPersistent byte = 0x01
100+ )
101+
90102// Manager is a struct that handles aliases for LND. It has an underlying
91103// database that can allocate aliases for channels, stores the peer's last
92104// alias for use in our hop hints, and contains mappings that both the Switch
@@ -146,6 +158,12 @@ func (m *Manager) populateMaps() error {
146158 // populate the Manager's actual maps.
147159 aliasMap := make (map [lnwire.ShortChannelID ]lnwire.ShortChannelID )
148160
161+ // This map tracks aliases that have the persistent flag set and should
162+ // remain in aliasToBase even after confirmation.
163+ persistentAliasMap := make (
164+ map [lnwire.ShortChannelID ]lnwire.ShortChannelID ,
165+ )
166+
149167 // This map caches the ChannelID/alias SCIDs stored in the database and
150168 // is used to populate the Manager's cache.
151169 peerAliasMap := make (map [lnwire.ChannelID ]lnwire.ShortChannelID )
@@ -177,14 +195,23 @@ func (m *Manager) populateMaps() error {
177195
178196 err = aliasToBaseBucket .ForEach (func (k , v []byte ) error {
179197 // The key will be the alias SCID and the value will be
180- // the base SCID.
198+ // the base SCID (8 bytes) optionally followed by flags
199+ // (1 byte).
181200 aliasScid := lnwire .NewShortChanIDFromInt (
182201 byteOrder .Uint64 (k ),
183202 )
184203 baseScid := lnwire .NewShortChanIDFromInt (
185- byteOrder .Uint64 (v ),
204+ byteOrder .Uint64 (v [: 8 ] ),
186205 )
187206 aliasMap [aliasScid ] = baseScid
207+
208+ // Check if the persistent flag is set. Backward
209+ // compatible: old entries have len(v) == 8, new entries
210+ // have len(v) == 9.
211+ if len (v ) > 8 && (v [8 ]& AliasFlagPersistent ) != 0 {
212+ persistentAliasMap [aliasScid ] = baseScid
213+ }
214+
188215 return nil
189216 })
190217 if err != nil {
@@ -214,6 +241,9 @@ func (m *Manager) populateMaps() error {
214241 }, func () {
215242 baseConfMap = make (map [lnwire.ShortChannelID ]struct {})
216243 aliasMap = make (map [lnwire.ShortChannelID ]lnwire.ShortChannelID )
244+ persistentAliasMap = make (
245+ map [lnwire.ShortChannelID ]lnwire.ShortChannelID ,
246+ )
217247 peerAliasMap = make (map [lnwire.ChannelID ]lnwire.ShortChannelID )
218248 })
219249 if err != nil {
@@ -233,6 +263,13 @@ func (m *Manager) populateMaps() error {
233263 m .aliasToBase [aliasSCID ] = baseSCID
234264 }
235265
266+ // Add persistent aliases to aliasToBase even if they're confirmed.
267+ // This allows FindBaseSCID to work for manually-added aliases that
268+ // should survive confirmation.
269+ for aliasSCID , baseSCID := range persistentAliasMap {
270+ m .aliasToBase [aliasSCID ] = baseSCID
271+ }
272+
236273 // Populate the peer alias cache.
237274 m .peerAlias = peerAliasMap
238275
@@ -252,7 +289,8 @@ type addAliasCfg struct {
252289type AddLocalAliasOption func (cfg * addAliasCfg )
253290
254291// WithBaseLookup is a functional option that controls whether a reverse lookup
255- // will be stored from the alias to the base scid.
292+ // will be stored from the alias to the base scid. This reverse lookup is
293+ // persisted and will not be wiped when the channel is confirmed.
256294func WithBaseLookup () AddLocalAliasOption {
257295 return func (cfg * addAliasCfg ) {
258296 cfg .baseLookup = true
@@ -268,7 +306,8 @@ func WithBaseLookup() AddLocalAliasOption {
268306//
269307// NOTE: The following aliases will not be persisted (will be lost on restart):
270308// - Aliases that were created without gossip flag.
271- // - Aliases that correspond to confirmed channels.
309+ // - Aliases that correspond to confirmed channels (unless WithBaseLookup
310+ // option is used).
272311func (m * Manager ) AddLocalAlias (alias , baseScid lnwire.ShortChannelID ,
273312 gossip , linkUpdate bool , opts ... AddLocalAliasOption ) error {
274313
@@ -315,14 +354,25 @@ func (m *Manager) AddLocalAlias(alias, baseScid lnwire.ShortChannelID,
315354 return err
316355 }
317356
318- var (
319- aliasBytes [8 ]byte
320- baseBytes [8 ]byte
321- )
322-
357+ var aliasBytes [8 ]byte
323358 byteOrder .PutUint64 (aliasBytes [:], alias .ToUint64 ())
324- byteOrder .PutUint64 (baseBytes [:], baseScid .ToUint64 ())
325- return aliasToBaseBucket .Put (aliasBytes [:], baseBytes [:])
359+
360+ // Write base SCID (8 bytes) + flags (1 byte).
361+ // Always write 9 bytes for consistency and future
362+ // extensibility.
363+ var valueBytes [9 ]byte
364+ byteOrder .PutUint64 (valueBytes [:8 ], baseScid .ToUint64 ())
365+
366+ // Set the persistent flag if baseLookup is requested.
367+ // The baseLookup option indicates this is a manually-added
368+ // alias that should persist even after confirmation.
369+ if cfg .baseLookup {
370+ valueBytes [8 ] = AliasFlagPersistent
371+ } else {
372+ valueBytes [8 ] = AliasFlagNone
373+ }
374+
375+ return aliasToBaseBucket .Put (aliasBytes [:], valueBytes [:])
326376 }, func () {})
327377 if err != nil {
328378 return err
@@ -404,20 +454,45 @@ func (m *Manager) DeleteSixConfs(baseScid lnwire.ShortChannelID) error {
404454
405455 var baseBytes [8 ]byte
406456 byteOrder .PutUint64 (baseBytes [:], baseScid .ToUint64 ())
407- return baseConfBucket .Put (baseBytes [:], []byte {})
457+ err = baseConfBucket .Put (baseBytes [:], []byte {})
458+ if err != nil {
459+ return err
460+ }
461+
462+ // Now we'll iterate over the alias bucket and delete all of
463+ // the aliases that do not have the persistency flag set.
464+ aliasToBaseBucket , err := tx .CreateTopLevelBucket (aliasBucket )
465+ if err != nil {
466+ return err
467+ }
468+
469+ return aliasToBaseBucket .ForEach (func (k , v []byte ) error {
470+ // Check if this entry maps to our baseScid.
471+ entryBase := lnwire .NewShortChanIDFromInt (
472+ byteOrder .Uint64 (v [:8 ]),
473+ )
474+ if entryBase .ToUint64 () != baseScid .ToUint64 () {
475+ return nil
476+ }
477+
478+ // Check whether the persistency flag is set.
479+ persist := len (v ) > 8 && (v [8 ]& AliasFlagPersistent ) != 0
480+
481+ aliasScid := lnwire .NewShortChanIDFromInt (
482+ byteOrder .Uint64 (k ),
483+ )
484+
485+ if ! persist {
486+ delete (m .aliasToBase , aliasScid )
487+ }
488+
489+ return nil
490+ })
408491 }, func () {})
409492 if err != nil {
410493 return err
411494 }
412495
413- // Now that the database state has been updated, we'll delete all of
414- // the aliasToBase mappings for this SCID.
415- for alias , base := range m .aliasToBase {
416- if base .ToUint64 () == baseScid .ToUint64 () {
417- delete (m .aliasToBase , alias )
418- }
419- }
420-
421496 return nil
422497}
423498
0 commit comments