@@ -4,12 +4,15 @@ import (
44 "math/rand"
55 "path/filepath"
66 "testing"
7+ "time"
78
89 "github.com/lightningnetwork/lnd/kvdb"
910 "github.com/lightningnetwork/lnd/lnwire"
1011 "github.com/stretchr/testify/require"
1112)
1213
14+ const channelReadTimeout = time .Second * 10
15+
1316// TestAliasStorePeerAlias tests that putting and retrieving a peer's alias
1417// works properly.
1518func TestAliasStorePeerAlias (t * testing.T ) {
@@ -116,7 +119,7 @@ func TestAliasLifecycle(t *testing.T) {
116119 require .NoError (t , err )
117120
118121 // The link updater should be called.
119- <- updateChan
122+ require . True ( t , readOrTimeout ( updateChan , channelReadTimeout ))
120123
121124 // Query the aliases and verify the results.
122125 aliasList := aliasStore .GetAliases (baseScid )
@@ -128,7 +131,7 @@ func TestAliasLifecycle(t *testing.T) {
128131 require .NoError (t , err )
129132
130133 // The link updater should be called.
131- <- updateChan
134+ require . True ( t , readOrTimeout ( updateChan , channelReadTimeout ))
132135
133136 // Query the aliases and verify the results.
134137 aliasList = aliasStore .GetAliases (baseScid )
@@ -141,7 +144,7 @@ func TestAliasLifecycle(t *testing.T) {
141144 require .NoError (t , err )
142145
143146 // The link updater should be called.
144- <- updateChan
147+ require . True ( t , readOrTimeout ( updateChan , channelReadTimeout ))
145148
146149 // We expect to get an error if we attempt to delete the same alias
147150 // again.
@@ -166,7 +169,7 @@ func TestAliasLifecycle(t *testing.T) {
166169 require .NoError (t , err )
167170
168171 // The link updater should be called.
169- <- updateChan
172+ require . True ( t , readOrTimeout ( updateChan , channelReadTimeout ))
170173
171174 // Query the aliases and verify that none exists.
172175 aliasList = aliasStore .GetAliases (baseScid )
@@ -180,7 +183,8 @@ func TestAliasLifecycle(t *testing.T) {
180183
181184 // We now manually add the next alias from the range as a custom alias.
182185 // This time we also use the base lookup option, in order to be able to
183- // go from alias back to the base scid.
186+ // go from alias back to the base scid. The WithBaseLookup option also
187+ // marks this alias as persistent.
184188 secondAlias := getNextScid (firstRequested )
185189 err = aliasStore .AddLocalAlias (
186190 secondAlias , baseScid , false , true , WithBaseLookup (),
@@ -266,3 +270,246 @@ func TestGetNextScid(t *testing.T) {
266270 })
267271 }
268272}
273+
274+ // TestPersistentAlias tests that aliases marked as persistent remain in the
275+ // aliasToBase map even after the base SCID is confirmed.
276+ func TestPersistentAlias (t * testing.T ) {
277+ t .Parallel ()
278+
279+ // Create the backend database and use this to create the aliasStore.
280+ dbPath := filepath .Join (t .TempDir (), "testdb" )
281+ db , err := kvdb .Create (
282+ kvdb .BoltBackendName , dbPath , true , kvdb .DefaultDBTimeout ,
283+ false ,
284+ )
285+ require .NoError (t , err )
286+ defer db .Close ()
287+
288+ linkUpdater := func (shortID lnwire.ShortChannelID ) error {
289+ return nil
290+ }
291+
292+ aliasStore , err := NewManager (db , linkUpdater )
293+ require .NoError (t , err )
294+
295+ const (
296+ base = uint64 (123123123 )
297+ nonPersistentAlias = uint64 (456456456 )
298+ persistentAlias = uint64 (789789789 )
299+ )
300+
301+ baseScid := lnwire .NewShortChanIDFromInt (base )
302+ nonPersistentScid := lnwire .NewShortChanIDFromInt (nonPersistentAlias )
303+ persistentScid := lnwire .NewShortChanIDFromInt (persistentAlias )
304+
305+ // Add a non-persistent alias (without WithBaseLookup option).
306+ err = aliasStore .AddLocalAlias (
307+ nonPersistentScid , baseScid , true , false ,
308+ )
309+ require .NoError (t , err )
310+
311+ // Add a persistent alias (with WithBaseLookup option).
312+ err = aliasStore .AddLocalAlias (
313+ persistentScid , baseScid , true , false , WithBaseLookup (),
314+ )
315+ require .NoError (t , err )
316+
317+ // Both aliases should be in aliasToBase before confirmation.
318+ _ , err = aliasStore .FindBaseSCID (nonPersistentScid )
319+ require .NoError (t , err )
320+
321+ _ , err = aliasStore .FindBaseSCID (persistentScid )
322+ require .NoError (t , err )
323+
324+ // Mark the base as confirmed (simulating 6 confirmations).
325+ err = aliasStore .DeleteSixConfs (baseScid )
326+ require .NoError (t , err )
327+
328+ // Non-persistent alias should no longer be findable.
329+ _ , err = aliasStore .FindBaseSCID (nonPersistentScid )
330+ require .Error (t , err )
331+
332+ // Persistent alias should still be findable.
333+ foundBase , err := aliasStore .FindBaseSCID (persistentScid )
334+ require .NoError (t , err )
335+ require .Equal (t , baseScid , foundBase )
336+
337+ // Restart: create a new manager with the same database.
338+ aliasStore2 , err := NewManager (db , linkUpdater )
339+ require .NoError (t , err )
340+
341+ // After restart, non-persistent alias should still not be findable.
342+ _ , err = aliasStore2 .FindBaseSCID (nonPersistentScid )
343+ require .Error (t , err )
344+
345+ // Persistent alias should still be findable after restart.
346+ foundBase , err = aliasStore2 .FindBaseSCID (persistentScid )
347+ require .NoError (t , err )
348+ require .Equal (t , baseScid , foundBase )
349+
350+ // Both aliases should still be in baseToSet.
351+ aliases := aliasStore2 .GetAliases (baseScid )
352+ require .Len (t , aliases , 2 )
353+ require .Contains (t , aliases , nonPersistentScid )
354+ require .Contains (t , aliases , persistentScid )
355+ }
356+
357+ // TestBackwardCompatibility tests that old aliases (without flags) are still
358+ // loaded correctly.
359+ func TestBackwardCompatibility (t * testing.T ) {
360+ t .Parallel ()
361+
362+ // Create the backend database and use this to create the aliasStore.
363+ dbPath := filepath .Join (t .TempDir (), "testdb" )
364+ db , err := kvdb .Create (
365+ kvdb .BoltBackendName , dbPath , true , kvdb .DefaultDBTimeout ,
366+ false ,
367+ )
368+ require .NoError (t , err )
369+ defer db .Close ()
370+
371+ linkUpdater := func (shortID lnwire.ShortChannelID ) error {
372+ return nil
373+ }
374+
375+ // Manually write an old-format alias (8 bytes, no flags).
376+ const (
377+ base = uint64 (111111111 )
378+ alias = uint64 (222222222 )
379+ )
380+
381+ err = kvdb .Update (db , func (tx kvdb.RwTx ) error {
382+ bucket , err := tx .CreateTopLevelBucket (aliasBucket )
383+ if err != nil {
384+ return err
385+ }
386+
387+ var aliasBytes [8 ]byte
388+ var baseBytes [8 ]byte
389+ byteOrder .PutUint64 (aliasBytes [:], alias )
390+ byteOrder .PutUint64 (baseBytes [:], base )
391+
392+ // Write only 8 bytes (old format, no flags).
393+ return bucket .Put (aliasBytes [:], baseBytes [:])
394+ }, func () {})
395+ require .NoError (t , err )
396+
397+ // Create the manager - it should load the old entry.
398+ aliasStore , err := NewManager (db , linkUpdater )
399+ require .NoError (t , err )
400+
401+ baseScid := lnwire .NewShortChanIDFromInt (base )
402+ aliasScid := lnwire .NewShortChanIDFromInt (alias )
403+
404+ // The alias should be in baseToSet.
405+ aliases := aliasStore .GetAliases (baseScid )
406+ require .Len (t , aliases , 1 )
407+ require .Contains (t , aliases , aliasScid )
408+
409+ // The alias should be findable (since it's not confirmed).
410+ foundBase , err := aliasStore .FindBaseSCID (aliasScid )
411+ require .NoError (t , err )
412+ require .Equal (t , baseScid , foundBase )
413+
414+ // Mark as confirmed - old aliases should not persist.
415+ err = aliasStore .DeleteSixConfs (baseScid )
416+ require .NoError (t , err )
417+
418+ // Should no longer be findable after confirmation.
419+ _ , err = aliasStore .FindBaseSCID (aliasScid )
420+ require .Error (t , err )
421+ }
422+
423+ // TestDeletePersistentAlias tests that persistent aliases can be manually
424+ // deleted via DeleteLocalAlias.
425+ func TestDeletePersistentAlias (t * testing.T ) {
426+ t .Parallel ()
427+
428+ // Create the backend database and use this to create the aliasStore.
429+ dbPath := filepath .Join (t .TempDir (), "testdb" )
430+ db , err := kvdb .Create (
431+ kvdb .BoltBackendName , dbPath , true , kvdb .DefaultDBTimeout ,
432+ false ,
433+ )
434+ require .NoError (t , err )
435+ defer db .Close ()
436+
437+ updateChan := make (chan struct {}, 1 )
438+ linkUpdater := func (shortID lnwire.ShortChannelID ) error {
439+ updateChan <- struct {}{}
440+ return nil
441+ }
442+
443+ aliasStore , err := NewManager (db , linkUpdater )
444+ require .NoError (t , err )
445+
446+ const (
447+ base = uint64 (123123123 )
448+ persistentAlias = uint64 (789789789 )
449+ )
450+
451+ baseScid := lnwire .NewShortChanIDFromInt (base )
452+ persistentScid := lnwire .NewShortChanIDFromInt (persistentAlias )
453+
454+ // Add a persistent alias (with WithBaseLookup option).
455+ err = aliasStore .AddLocalAlias (
456+ persistentScid , baseScid , true , true , WithBaseLookup (),
457+ )
458+ require .NoError (t , err )
459+
460+ // Link updater should be called.
461+ require .True (t , readOrTimeout (updateChan , channelReadTimeout ))
462+
463+ // Alias should be findable.
464+ foundBase , err := aliasStore .FindBaseSCID (persistentScid )
465+ require .NoError (t , err )
466+ require .Equal (t , baseScid , foundBase )
467+
468+ // Mark as confirmed - persistent alias should survive.
469+ err = aliasStore .DeleteSixConfs (baseScid )
470+ require .NoError (t , err )
471+
472+ // Persistent alias should still be findable after confirmation.
473+ foundBase , err = aliasStore .FindBaseSCID (persistentScid )
474+ require .NoError (t , err )
475+ require .Equal (t , baseScid , foundBase )
476+
477+ // Now manually delete the persistent alias.
478+ err = aliasStore .DeleteLocalAlias (persistentScid , baseScid )
479+ require .NoError (t , err )
480+
481+ // Link updater should be called.
482+ require .True (t , readOrTimeout (updateChan , channelReadTimeout ))
483+
484+ // Alias should no longer be findable.
485+ _ , err = aliasStore .FindBaseSCID (persistentScid )
486+ require .Error (t , err )
487+
488+ // Alias should not be in baseToSet.
489+ aliases := aliasStore .GetAliases (baseScid )
490+ require .Len (t , aliases , 0 )
491+
492+ // Verify it's deleted from database by restarting.
493+ aliasStore2 , err := NewManager (db , linkUpdater )
494+ require .NoError (t , err )
495+
496+ // Should still not be findable after restart.
497+ _ , err = aliasStore2 .FindBaseSCID (persistentScid )
498+ require .Error (t , err )
499+
500+ // Should not be in baseToSet after restart.
501+ aliases = aliasStore2 .GetAliases (baseScid )
502+ require .Len (t , aliases , 0 )
503+ }
504+
505+ // readOrTimeout attempts to read an element from the given channel of type T.
506+ // If the item is read successfully then true is returned. If the timeout is
507+ // reached then it returns false.
508+ func readOrTimeout [T any ](ch <- chan T , timeout time.Duration ) bool {
509+ select {
510+ case <- ch :
511+ return true
512+ case <- time .After (timeout ):
513+ return false
514+ }
515+ }
0 commit comments