@@ -180,7 +180,8 @@ func TestAliasLifecycle(t *testing.T) {
180180
181181 // We now manually add the next alias from the range as a custom alias.
182182 // This time we also use the base lookup option, in order to be able to
183- // go from alias back to the base scid.
183+ // go from alias back to the base scid. The WithBaseLookup option also
184+ // marks this alias as persistent.
184185 secondAlias := getNextScid (firstRequested )
185186 err = aliasStore .AddLocalAlias (
186187 secondAlias , baseScid , false , true , WithBaseLookup (),
@@ -266,3 +267,234 @@ func TestGetNextScid(t *testing.T) {
266267 })
267268 }
268269}
270+
271+ // TestPersistentAlias tests that aliases marked as persistent remain in the
272+ // aliasToBase map even after the base SCID is confirmed.
273+ func TestPersistentAlias (t * testing.T ) {
274+ t .Parallel ()
275+
276+ // Create the backend database and use this to create the aliasStore.
277+ dbPath := filepath .Join (t .TempDir (), "testdb" )
278+ db , err := kvdb .Create (
279+ kvdb .BoltBackendName , dbPath , true , kvdb .DefaultDBTimeout ,
280+ false ,
281+ )
282+ require .NoError (t , err )
283+ defer db .Close ()
284+
285+ linkUpdater := func (shortID lnwire.ShortChannelID ) error {
286+ return nil
287+ }
288+
289+ aliasStore , err := NewManager (db , linkUpdater )
290+ require .NoError (t , err )
291+
292+ const (
293+ base = uint64 (123123123 )
294+ nonPersistentAlias = uint64 (456456456 )
295+ persistentAlias = uint64 (789789789 )
296+ )
297+
298+ baseScid := lnwire .NewShortChanIDFromInt (base )
299+ nonPersistentScid := lnwire .NewShortChanIDFromInt (nonPersistentAlias )
300+ persistentScid := lnwire .NewShortChanIDFromInt (persistentAlias )
301+
302+ // Add a non-persistent alias (without WithBaseLookup option).
303+ err = aliasStore .AddLocalAlias (
304+ nonPersistentScid , baseScid , true , false ,
305+ )
306+ require .NoError (t , err )
307+
308+ // Add a persistent alias (with WithBaseLookup option).
309+ err = aliasStore .AddLocalAlias (
310+ persistentScid , baseScid , true , false , WithBaseLookup (),
311+ )
312+ require .NoError (t , err )
313+
314+ // Both aliases should be in aliasToBase before confirmation.
315+ _ , err = aliasStore .FindBaseSCID (nonPersistentScid )
316+ require .NoError (t , err )
317+
318+ _ , err = aliasStore .FindBaseSCID (persistentScid )
319+ require .NoError (t , err )
320+
321+ // Mark the base as confirmed (simulating 6 confirmations).
322+ err = aliasStore .DeleteSixConfs (baseScid )
323+ require .NoError (t , err )
324+
325+ // Non-persistent alias should no longer be findable.
326+ _ , err = aliasStore .FindBaseSCID (nonPersistentScid )
327+ require .Error (t , err )
328+
329+ // Persistent alias should still be findable.
330+ foundBase , err := aliasStore .FindBaseSCID (persistentScid )
331+ require .NoError (t , err )
332+ require .Equal (t , baseScid , foundBase )
333+
334+ // Restart: create a new manager with the same database.
335+ aliasStore2 , err := NewManager (db , linkUpdater )
336+ require .NoError (t , err )
337+
338+ // After restart, non-persistent alias should still not be findable.
339+ _ , err = aliasStore2 .FindBaseSCID (nonPersistentScid )
340+ require .Error (t , err )
341+
342+ // Persistent alias should still be findable after restart.
343+ foundBase , err = aliasStore2 .FindBaseSCID (persistentScid )
344+ require .NoError (t , err )
345+ require .Equal (t , baseScid , foundBase )
346+
347+ // Both aliases should still be in baseToSet.
348+ aliases := aliasStore2 .GetAliases (baseScid )
349+ require .Len (t , aliases , 2 )
350+ require .Contains (t , aliases , nonPersistentScid )
351+ require .Contains (t , aliases , persistentScid )
352+ }
353+
354+ // TestBackwardCompatibility tests that old aliases (without flags) are still
355+ // loaded correctly.
356+ func TestBackwardCompatibility (t * testing.T ) {
357+ t .Parallel ()
358+
359+ // Create the backend database and use this to create the aliasStore.
360+ dbPath := filepath .Join (t .TempDir (), "testdb" )
361+ db , err := kvdb .Create (
362+ kvdb .BoltBackendName , dbPath , true , kvdb .DefaultDBTimeout ,
363+ false ,
364+ )
365+ require .NoError (t , err )
366+ defer db .Close ()
367+
368+ linkUpdater := func (shortID lnwire.ShortChannelID ) error {
369+ return nil
370+ }
371+
372+ // Manually write an old-format alias (8 bytes, no flags).
373+ const (
374+ base = uint64 (111111111 )
375+ alias = uint64 (222222222 )
376+ )
377+
378+ err = kvdb .Update (db , func (tx kvdb.RwTx ) error {
379+ bucket , err := tx .CreateTopLevelBucket (aliasBucket )
380+ if err != nil {
381+ return err
382+ }
383+
384+ var aliasBytes [8 ]byte
385+ var baseBytes [8 ]byte
386+ byteOrder .PutUint64 (aliasBytes [:], alias )
387+ byteOrder .PutUint64 (baseBytes [:], base )
388+
389+ // Write only 8 bytes (old format, no flags).
390+ return bucket .Put (aliasBytes [:], baseBytes [:])
391+ }, func () {})
392+ require .NoError (t , err )
393+
394+ // Create the manager - it should load the old entry.
395+ aliasStore , err := NewManager (db , linkUpdater )
396+ require .NoError (t , err )
397+
398+ baseScid := lnwire .NewShortChanIDFromInt (base )
399+ aliasScid := lnwire .NewShortChanIDFromInt (alias )
400+
401+ // The alias should be in baseToSet.
402+ aliases := aliasStore .GetAliases (baseScid )
403+ require .Len (t , aliases , 1 )
404+ require .Contains (t , aliases , aliasScid )
405+
406+ // The alias should be findable (since it's not confirmed).
407+ foundBase , err := aliasStore .FindBaseSCID (aliasScid )
408+ require .NoError (t , err )
409+ require .Equal (t , baseScid , foundBase )
410+
411+ // Mark as confirmed - old aliases should not persist.
412+ err = aliasStore .DeleteSixConfs (baseScid )
413+ require .NoError (t , err )
414+
415+ // Should no longer be findable after confirmation.
416+ _ , err = aliasStore .FindBaseSCID (aliasScid )
417+ require .Error (t , err )
418+ }
419+
420+ // TestDeletePersistentAlias tests that persistent aliases can be manually
421+ // deleted via DeleteLocalAlias.
422+ func TestDeletePersistentAlias (t * testing.T ) {
423+ t .Parallel ()
424+
425+ // Create the backend database and use this to create the aliasStore.
426+ dbPath := filepath .Join (t .TempDir (), "testdb" )
427+ db , err := kvdb .Create (
428+ kvdb .BoltBackendName , dbPath , true , kvdb .DefaultDBTimeout ,
429+ false ,
430+ )
431+ require .NoError (t , err )
432+ defer db .Close ()
433+
434+ updateChan := make (chan struct {}, 1 )
435+ linkUpdater := func (shortID lnwire.ShortChannelID ) error {
436+ updateChan <- struct {}{}
437+ return nil
438+ }
439+
440+ aliasStore , err := NewManager (db , linkUpdater )
441+ require .NoError (t , err )
442+
443+ const (
444+ base = uint64 (123123123 )
445+ persistentAlias = uint64 (789789789 )
446+ )
447+
448+ baseScid := lnwire .NewShortChanIDFromInt (base )
449+ persistentScid := lnwire .NewShortChanIDFromInt (persistentAlias )
450+
451+ // Add a persistent alias (with WithBaseLookup option).
452+ err = aliasStore .AddLocalAlias (
453+ persistentScid , baseScid , true , true , WithBaseLookup (),
454+ )
455+ require .NoError (t , err )
456+
457+ // Link updater should be called.
458+ <- updateChan
459+
460+ // Alias should be findable.
461+ foundBase , err := aliasStore .FindBaseSCID (persistentScid )
462+ require .NoError (t , err )
463+ require .Equal (t , baseScid , foundBase )
464+
465+ // Mark as confirmed - persistent alias should survive.
466+ err = aliasStore .DeleteSixConfs (baseScid )
467+ require .NoError (t , err )
468+
469+ // Persistent alias should still be findable after confirmation.
470+ foundBase , err = aliasStore .FindBaseSCID (persistentScid )
471+ require .NoError (t , err )
472+ require .Equal (t , baseScid , foundBase )
473+
474+ // Now manually delete the persistent alias.
475+ err = aliasStore .DeleteLocalAlias (persistentScid , baseScid )
476+ require .NoError (t , err )
477+
478+ // Link updater should be called.
479+ <- updateChan
480+
481+ // Alias should no longer be findable.
482+ _ , err = aliasStore .FindBaseSCID (persistentScid )
483+ require .Error (t , err )
484+
485+ // Alias should not be in baseToSet.
486+ aliases := aliasStore .GetAliases (baseScid )
487+ require .Len (t , aliases , 0 )
488+
489+ // Verify it's deleted from database by restarting.
490+ aliasStore2 , err := NewManager (db , linkUpdater )
491+ require .NoError (t , err )
492+
493+ // Should still not be findable after restart.
494+ _ , err = aliasStore2 .FindBaseSCID (persistentScid )
495+ require .Error (t , err )
496+
497+ // Should not be in baseToSet after restart.
498+ aliases = aliasStore2 .GetAliases (baseScid )
499+ require .Len (t , aliases , 0 )
500+ }
0 commit comments