Skip to content

Commit 6675808

Browse files
committed
aliasmgr: add test coverage for alias persistency
1 parent 83f9ab0 commit 6675808

File tree

1 file changed

+252
-5
lines changed

1 file changed

+252
-5
lines changed

aliasmgr/aliasmgr_test.go

Lines changed: 252 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -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.
1518
func 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

Comments
 (0)