Skip to content

Commit 31a6f87

Browse files
authored
Merge pull request #9049 from lightningnetwork/extract-part2-from-staging-branch
[custom channels 2/5]: Extract PART2 from mega staging branch
2 parents 6747fc1 + 427d41d commit 31a6f87

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

68 files changed

+6786
-2705
lines changed

aliasmgr/aliasmgr.go

Lines changed: 189 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -5,11 +5,22 @@ import (
55
"fmt"
66
"sync"
77

8+
"github.com/lightningnetwork/lnd/fn"
89
"github.com/lightningnetwork/lnd/htlcswitch/hop"
910
"github.com/lightningnetwork/lnd/kvdb"
1011
"github.com/lightningnetwork/lnd/lnwire"
12+
"golang.org/x/exp/maps"
1113
)
1214

15+
// UpdateLinkAliases is a function type for a function that locates the active
16+
// link that matches the given shortID and triggers an update based on the
17+
// latest values of the alias manager.
18+
type UpdateLinkAliases func(shortID lnwire.ShortChannelID) error
19+
20+
// ScidAliasMap is a map from a base short channel ID to a set of alias short
21+
// channel IDs.
22+
type ScidAliasMap map[lnwire.ShortChannelID][]lnwire.ShortChannelID
23+
1324
var (
1425
// aliasBucket stores aliases as keys and their base SCIDs as values.
1526
// This is used to populate the maps that the Manager uses. The keys
@@ -47,17 +58,18 @@ var (
4758
// operations.
4859
byteOrder = binary.BigEndian
4960

50-
// startBlockHeight is the starting block height of the alias range.
51-
startingBlockHeight = 16_000_000
61+
// AliasStartBlockHeight is the starting block height of the alias
62+
// range.
63+
AliasStartBlockHeight uint32 = 16_000_000
5264

53-
// endBlockHeight is the ending block height of the alias range.
54-
endBlockHeight = 16_250_000
65+
// AliasEndBlockHeight is the ending block height of the alias range.
66+
AliasEndBlockHeight uint32 = 16_250_000
5567

5668
// StartingAlias is the first alias ShortChannelID that will get
5769
// assigned by RequestAlias. The starting BlockHeight is chosen so that
5870
// legitimate SCIDs in integration tests aren't mistaken for an alias.
5971
StartingAlias = lnwire.ShortChannelID{
60-
BlockHeight: uint32(startingBlockHeight),
72+
BlockHeight: AliasStartBlockHeight,
6173
TxIndex: 0,
6274
TxPosition: 0,
6375
}
@@ -68,6 +80,10 @@ var (
6880
// errNoPeerAlias is returned when the peer's alias for a given
6981
// channel is not found.
7082
errNoPeerAlias = fmt.Errorf("no peer alias found")
83+
84+
// ErrAliasNotFound is returned when the alias is not found and can't
85+
// be mapped to a base SCID.
86+
ErrAliasNotFound = fmt.Errorf("alias not found")
7187
)
7288

7389
// Manager is a struct that handles aliases for LND. It has an underlying
@@ -77,10 +93,14 @@ var (
7793
type Manager struct {
7894
backend kvdb.Backend
7995

96+
// linkAliasUpdater is a function used by the alias manager to
97+
// facilitate live update of aliases in other subsystems.
98+
linkAliasUpdater UpdateLinkAliases
99+
80100
// baseToSet is a mapping from the "base" SCID to the set of aliases
81101
// for this channel. This mapping includes all channels that
82102
// negotiated the option-scid-alias feature bit.
83-
baseToSet map[lnwire.ShortChannelID][]lnwire.ShortChannelID
103+
baseToSet ScidAliasMap
84104

85105
// aliasToBase is a mapping that maps all aliases for a given channel
86106
// to its base SCID. This is only used for channels that have
@@ -98,9 +118,15 @@ type Manager struct {
98118
}
99119

100120
// NewManager initializes an alias Manager from the passed database backend.
101-
func NewManager(db kvdb.Backend) (*Manager, error) {
102-
m := &Manager{backend: db}
103-
m.baseToSet = make(map[lnwire.ShortChannelID][]lnwire.ShortChannelID)
121+
func NewManager(db kvdb.Backend, linkAliasUpdater UpdateLinkAliases) (*Manager,
122+
error) {
123+
124+
m := &Manager{
125+
backend: db,
126+
baseToSet: make(ScidAliasMap),
127+
linkAliasUpdater: linkAliasUpdater,
128+
}
129+
104130
m.aliasToBase = make(map[lnwire.ShortChannelID]lnwire.ShortChannelID)
105131
m.peerAlias = make(map[lnwire.ChannelID]lnwire.ShortChannelID)
106132

@@ -215,12 +241,22 @@ func (m *Manager) populateMaps() error {
215241
// AddLocalAlias adds a database mapping from the passed alias to the passed
216242
// base SCID. The gossip boolean marks whether or not to create a mapping
217243
// that the gossiper will use. It is set to false for the upgrade path where
218-
// the feature-bit is toggled on and there are existing channels.
244+
// the feature-bit is toggled on and there are existing channels. The linkUpdate
245+
// flag is used to signal whether this function should also trigger an update
246+
// on the htlcswitch scid alias maps.
219247
func (m *Manager) AddLocalAlias(alias, baseScid lnwire.ShortChannelID,
220-
gossip bool) error {
248+
gossip, linkUpdate bool) error {
221249

250+
// We need to lock the manager for the whole duration of this method,
251+
// except for the very last part where we call the link updater. In
252+
// order for us to safely use a defer _and_ still be able to manually
253+
// unlock, we use a sync.Once.
222254
m.Lock()
223-
defer m.Unlock()
255+
unlockOnce := sync.Once{}
256+
unlock := func() {
257+
unlockOnce.Do(m.Unlock)
258+
}
259+
defer unlock()
224260

225261
err := kvdb.Update(m.backend, func(tx kvdb.RwTx) error {
226262
// If the caller does not want to allow the alias to be used
@@ -270,6 +306,18 @@ func (m *Manager) AddLocalAlias(alias, baseScid lnwire.ShortChannelID,
270306
m.aliasToBase[alias] = baseScid
271307
}
272308

309+
// We definitely need to unlock the Manager before calling the link
310+
// updater. If we don't, we'll deadlock. We use a sync.Once to ensure
311+
// that we only unlock once.
312+
unlock()
313+
314+
// Finally, we trigger a htlcswitch update if the flag is set, in order
315+
// for any future htlc that references the added alias to be properly
316+
// routed.
317+
if linkUpdate {
318+
return m.linkAliasUpdater(baseScid)
319+
}
320+
273321
return nil
274322
}
275323

@@ -340,6 +388,74 @@ func (m *Manager) DeleteSixConfs(baseScid lnwire.ShortChannelID) error {
340388
return nil
341389
}
342390

391+
// DeleteLocalAlias removes a mapping from the database and the Manager's maps.
392+
func (m *Manager) DeleteLocalAlias(alias,
393+
baseScid lnwire.ShortChannelID) error {
394+
395+
// We need to lock the manager for the whole duration of this method,
396+
// except for the very last part where we call the link updater. In
397+
// order for us to safely use a defer _and_ still be able to manually
398+
// unlock, we use a sync.Once.
399+
m.Lock()
400+
unlockOnce := sync.Once{}
401+
unlock := func() {
402+
unlockOnce.Do(m.Unlock)
403+
}
404+
defer unlock()
405+
406+
err := kvdb.Update(m.backend, func(tx kvdb.RwTx) error {
407+
aliasToBaseBucket, err := tx.CreateTopLevelBucket(aliasBucket)
408+
if err != nil {
409+
return err
410+
}
411+
412+
var aliasBytes [8]byte
413+
byteOrder.PutUint64(aliasBytes[:], alias.ToUint64())
414+
415+
// If the user attempts to delete an alias that doesn't exist,
416+
// we'll want to inform them about it and not just do nothing.
417+
if aliasToBaseBucket.Get(aliasBytes[:]) == nil {
418+
return ErrAliasNotFound
419+
}
420+
421+
return aliasToBaseBucket.Delete(aliasBytes[:])
422+
}, func() {})
423+
if err != nil {
424+
return err
425+
}
426+
427+
// Now that the database state has been updated, we'll delete the
428+
// mapping from the Manager's maps.
429+
aliasSet, ok := m.baseToSet[baseScid]
430+
if !ok {
431+
return ErrAliasNotFound
432+
}
433+
434+
// We'll filter the alias set and remove the alias from it.
435+
aliasSet = fn.Filter(func(a lnwire.ShortChannelID) bool {
436+
return a.ToUint64() != alias.ToUint64()
437+
}, aliasSet)
438+
439+
// If the alias set is empty, we'll delete the base SCID from the
440+
// baseToSet map.
441+
if len(aliasSet) == 0 {
442+
delete(m.baseToSet, baseScid)
443+
} else {
444+
m.baseToSet[baseScid] = aliasSet
445+
}
446+
447+
// Finally, we'll delete the aliasToBase mapping from the Manager's
448+
// cache (but this is only set if we gossip the alias).
449+
delete(m.aliasToBase, alias)
450+
451+
// We definitely need to unlock the Manager before calling the link
452+
// updater. If we don't, we'll deadlock. We use a sync.Once to ensure
453+
// that we only unlock once.
454+
unlock()
455+
456+
return m.linkAliasUpdater(baseScid)
457+
}
458+
343459
// PutPeerAlias stores the peer's alias SCID once we learn of it in the
344460
// channel_ready message.
345461
func (m *Manager) PutPeerAlias(chanID lnwire.ChannelID,
@@ -392,6 +508,19 @@ func (m *Manager) GetPeerAlias(chanID lnwire.ChannelID) (lnwire.ShortChannelID,
392508
func (m *Manager) RequestAlias() (lnwire.ShortChannelID, error) {
393509
var nextAlias lnwire.ShortChannelID
394510

511+
m.RLock()
512+
defer m.RUnlock()
513+
514+
// haveAlias returns true if the passed alias is already assigned to a
515+
// channel in the baseToSet map.
516+
haveAlias := func(maybeNextAlias lnwire.ShortChannelID) bool {
517+
return fn.Any(func(aliasList []lnwire.ShortChannelID) bool {
518+
return fn.Any(func(alias lnwire.ShortChannelID) bool {
519+
return alias == maybeNextAlias
520+
}, aliasList)
521+
}, maps.Values(m.baseToSet))
522+
}
523+
395524
err := kvdb.Update(m.backend, func(tx kvdb.RwTx) error {
396525
bucket, err := tx.CreateTopLevelBucket(aliasAllocBucket)
397526
if err != nil {
@@ -404,6 +533,29 @@ func (m *Manager) RequestAlias() (lnwire.ShortChannelID, error) {
404533
// StartingAlias to it.
405534
nextAlias = StartingAlias
406535

536+
// If the very first alias is already assigned, we'll
537+
// keep incrementing until we find an unassigned alias.
538+
// This is to avoid collision with custom added SCID
539+
// aliases that fall into the same range as the ones we
540+
// generate here monotonically. Those custom SCIDs are
541+
// stored in a different bucket, but we can just check
542+
// the in-memory map for simplicity.
543+
for {
544+
if !haveAlias(nextAlias) {
545+
break
546+
}
547+
548+
nextAlias = getNextScid(nextAlias)
549+
550+
// Abort if we've reached the end of the range.
551+
if nextAlias.BlockHeight >=
552+
AliasEndBlockHeight {
553+
554+
return fmt.Errorf("range for custom " +
555+
"aliases exhausted")
556+
}
557+
}
558+
407559
var scratch [8]byte
408560
byteOrder.PutUint64(scratch[:], nextAlias.ToUint64())
409561
return bucket.Put(lastAliasKey, scratch[:])
@@ -418,6 +570,26 @@ func (m *Manager) RequestAlias() (lnwire.ShortChannelID, error) {
418570
)
419571
nextAlias = getNextScid(lastScid)
420572

573+
// If the next alias is already assigned, we'll keep
574+
// incrementing until we find an unassigned alias. This is to
575+
// avoid collision with custom added SCID aliases that fall into
576+
// the same range as the ones we generate here monotonically.
577+
// Those custom SCIDs are stored in a different bucket, but we
578+
// can just check the in-memory map for simplicity.
579+
for {
580+
if !haveAlias(nextAlias) {
581+
break
582+
}
583+
584+
nextAlias = getNextScid(nextAlias)
585+
586+
// Abort if we've reached the end of the range.
587+
if nextAlias.BlockHeight >= AliasEndBlockHeight {
588+
return fmt.Errorf("range for custom " +
589+
"aliases exhausted")
590+
}
591+
}
592+
421593
var scratch [8]byte
422594
byteOrder.PutUint64(scratch[:], nextAlias.ToUint64())
423595
return bucket.Put(lastAliasKey, scratch[:])
@@ -433,11 +605,11 @@ func (m *Manager) RequestAlias() (lnwire.ShortChannelID, error) {
433605

434606
// ListAliases returns a carbon copy of baseToSet. This is used by the rpc
435607
// layer.
436-
func (m *Manager) ListAliases() map[lnwire.ShortChannelID][]lnwire.ShortChannelID {
608+
func (m *Manager) ListAliases() ScidAliasMap {
437609
m.RLock()
438610
defer m.RUnlock()
439611

440-
baseCopy := make(map[lnwire.ShortChannelID][]lnwire.ShortChannelID)
612+
baseCopy := make(ScidAliasMap)
441613

442614
for k, v := range m.baseToSet {
443615
setCopy := make([]lnwire.ShortChannelID, len(v))
@@ -496,10 +668,10 @@ func getNextScid(last lnwire.ShortChannelID) lnwire.ShortChannelID {
496668

497669
// IsAlias returns true if the passed SCID is an alias. The function determines
498670
// this by looking at the BlockHeight. If the BlockHeight is greater than
499-
// startingBlockHeight and less than endBlockHeight, then it is an alias
671+
// AliasStartBlockHeight and less than AliasEndBlockHeight, then it is an alias
500672
// assigned by RequestAlias. These bounds only apply to aliases we generate.
501673
// Our peers are free to use any range they choose.
502674
func IsAlias(scid lnwire.ShortChannelID) bool {
503-
return scid.BlockHeight >= uint32(startingBlockHeight) &&
504-
scid.BlockHeight < uint32(endBlockHeight)
675+
return scid.BlockHeight >= AliasStartBlockHeight &&
676+
scid.BlockHeight < AliasEndBlockHeight
505677
}

0 commit comments

Comments
 (0)