Skip to content

Commit 5c1b568

Browse files
GeorgeTsagkguggero
authored andcommitted
multi: refresh htlcswitch aliases on aliasmgr update
1 parent cc12fb3 commit 5c1b568

File tree

8 files changed

+133
-18
lines changed

8 files changed

+133
-18
lines changed

aliasmgr/aliasmgr.go

Lines changed: 53 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,11 @@ import (
1010
"github.com/lightningnetwork/lnd/lnwire"
1111
)
1212

13+
// UpdateLinkAliases locates the active link that matches the given
14+
// shortID and triggers an update based on the latest values of the
15+
// alias manager.
16+
type UpdateLinkAliases func(shortID lnwire.ShortChannelID) error
17+
1318
var (
1419
// aliasBucket stores aliases as keys and their base SCIDs as values.
1520
// This is used to populate the maps that the Manager uses. The keys
@@ -77,6 +82,10 @@ var (
7782
type Manager struct {
7883
backend kvdb.Backend
7984

85+
// LinkUpdater is a function used by aliasmgr to facilitate live update
86+
// of aliases in other subsystems.
87+
LinkUpdater UpdateLinkAliases
88+
8089
// baseToSet is a mapping from the "base" SCID to the set of aliases
8190
// for this channel. This mapping includes all channels that
8291
// negotiated the option-scid-alias feature bit.
@@ -98,11 +107,14 @@ type Manager struct {
98107
}
99108

100109
// NewManager initializes an alias Manager from the passed database backend.
101-
func NewManager(db kvdb.Backend) (*Manager, error) {
110+
func NewManager(db kvdb.Backend,
111+
linkUpdater UpdateLinkAliases) (*Manager, error) {
112+
102113
m := &Manager{backend: db}
103114
m.baseToSet = make(map[lnwire.ShortChannelID][]lnwire.ShortChannelID)
104115
m.aliasToBase = make(map[lnwire.ShortChannelID]lnwire.ShortChannelID)
105116
m.peerAlias = make(map[lnwire.ChannelID]lnwire.ShortChannelID)
117+
m.LinkUpdater = linkUpdater
106118

107119
err := m.populateMaps()
108120
return m, err
@@ -215,12 +227,22 @@ func (m *Manager) populateMaps() error {
215227
// AddLocalAlias adds a database mapping from the passed alias to the passed
216228
// base SCID. The gossip boolean marks whether or not to create a mapping
217229
// 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.
230+
// the feature-bit is toggled on and there are existing channels. The linkUpdate
231+
// flag is used to signal whether this function should also trigger an update
232+
// on the htlcswitch scid alias maps.
219233
func (m *Manager) AddLocalAlias(alias, baseScid lnwire.ShortChannelID,
220-
gossip bool) error {
234+
gossip, linkUpdate bool) error {
221235

236+
// We need to lock the manager for the whole duration of this method,
237+
// except for the very last part where we call the link updater. In
238+
// order for us to safely use a defer _and_ still be able to manually
239+
// unlock, we use a sync.Once.
222240
m.Lock()
223-
defer m.Unlock()
241+
unlockOnce := sync.Once{}
242+
unlock := func() {
243+
unlockOnce.Do(m.Unlock)
244+
}
245+
defer unlock()
224246

225247
err := kvdb.Update(m.backend, func(tx kvdb.RwTx) error {
226248
// If the caller does not want to allow the alias to be used
@@ -270,6 +292,18 @@ func (m *Manager) AddLocalAlias(alias, baseScid lnwire.ShortChannelID,
270292
m.aliasToBase[alias] = baseScid
271293
}
272294

295+
// We definitely need to unlock the Manager before calling the link
296+
// updater. If we don't, we'll deadlock. We use a sync.Once to ensure
297+
// that we only unlock once.
298+
unlock()
299+
300+
// Finally, we trigger a htlcswitch update if the flag is set, in order
301+
// for any future htlc that references the added alias to be properly
302+
// routed.
303+
if linkUpdate {
304+
return m.LinkUpdater(baseScid)
305+
}
306+
273307
return nil
274308
}
275309

@@ -344,8 +378,16 @@ func (m *Manager) DeleteSixConfs(baseScid lnwire.ShortChannelID) error {
344378
func (m *Manager) DeleteLocalAlias(alias,
345379
baseScid lnwire.ShortChannelID) error {
346380

381+
// We need to lock the manager for the whole duration of this method,
382+
// except for the very last part where we call the link updater. In
383+
// order for us to safely use a defer _and_ still be able to manually
384+
// unlock, we use a sync.Once.
347385
m.Lock()
348-
defer m.Unlock()
386+
unlockOnce := sync.Once{}
387+
unlock := func() {
388+
unlockOnce.Do(m.Unlock)
389+
}
390+
defer unlock()
349391

350392
err := kvdb.Update(m.backend, func(tx kvdb.RwTx) error {
351393
aliasToBaseBucket, err := tx.CreateTopLevelBucket(aliasBucket)
@@ -390,7 +432,12 @@ func (m *Manager) DeleteLocalAlias(alias,
390432
// cache.
391433
delete(m.aliasToBase, alias)
392434

393-
return nil
435+
// We definitely need to unlock the Manager before calling the link
436+
// updater. If we don't, we'll deadlock. We use a sync.Once to ensure
437+
// that we only unlock once.
438+
unlock()
439+
440+
return m.LinkUpdater(baseScid)
394441
}
395442

396443
// PutPeerAlias stores the peer's alias SCID once we learn of it in the

aliasmgr/aliasmgr_test.go

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,11 @@ func TestAliasStorePeerAlias(t *testing.T) {
2323
require.NoError(t, err)
2424
defer db.Close()
2525

26-
aliasStore, err := NewManager(db)
26+
linkUpdater := func(shortID lnwire.ShortChannelID) error {
27+
return nil
28+
}
29+
30+
aliasStore, err := NewManager(db, linkUpdater)
2731
require.NoError(t, err)
2832

2933
var chanID1 [32]byte
@@ -52,7 +56,11 @@ func TestAliasStoreRequest(t *testing.T) {
5256
require.NoError(t, err)
5357
defer db.Close()
5458

55-
aliasStore, err := NewManager(db)
59+
linkUpdater := func(shortID lnwire.ShortChannelID) error {
60+
return nil
61+
}
62+
63+
aliasStore, err := NewManager(db, linkUpdater)
5664
require.NoError(t, err)
5765

5866
// We'll assert that the very first alias we receive is StartingAlias.

funding/interfaces.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,8 @@ type aliasHandler interface {
3636
GetPeerAlias(lnwire.ChannelID) (lnwire.ShortChannelID, error)
3737

3838
// AddLocalAlias persists an alias to an underlying alias store.
39-
AddLocalAlias(lnwire.ShortChannelID, lnwire.ShortChannelID, bool) error
39+
AddLocalAlias(lnwire.ShortChannelID, lnwire.ShortChannelID, bool,
40+
bool) error
4041

4142
// GetAliases returns the set of aliases given the main SCID of a
4243
// channel. This SCID will be an alias for zero-conf channels and will

funding/manager.go

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1249,7 +1249,7 @@ func (f *Manager) advancePendingChannelState(
12491249
// Persist the alias to the alias database.
12501250
baseScid := channel.ShortChannelID
12511251
err := f.cfg.AliasManager.AddLocalAlias(
1252-
baseScid, baseScid, true,
1252+
baseScid, baseScid, true, false,
12531253
)
12541254
if err != nil {
12551255
return fmt.Errorf("error adding local alias to "+
@@ -3108,7 +3108,7 @@ func (f *Manager) handleFundingConfirmation(
31083108
}
31093109

31103110
err = f.cfg.AliasManager.AddLocalAlias(
3111-
aliasScid, confChannel.shortChanID, true,
3111+
aliasScid, confChannel.shortChanID, true, false,
31123112
)
31133113
if err != nil {
31143114
return fmt.Errorf("unable to request alias: %w", err)
@@ -3274,7 +3274,7 @@ func (f *Manager) sendChannelReady(completeChan *channeldb.OpenChannel,
32743274

32753275
err = f.cfg.AliasManager.AddLocalAlias(
32763276
alias, completeChan.ShortChannelID,
3277-
false,
3277+
false, false,
32783278
)
32793279
if err != nil {
32803280
return err
@@ -3853,7 +3853,7 @@ func (f *Manager) handleChannelReady(peer lnpeer.Peer, //nolint:funlen
38533853
}
38543854

38553855
err = f.cfg.AliasManager.AddLocalAlias(
3856-
alias, channel.ShortChannelID, false,
3856+
alias, channel.ShortChannelID, false, false,
38573857
)
38583858
if err != nil {
38593859
log.Errorf("unable to add local alias: %v",

funding/manager_test.go

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -161,7 +161,7 @@ func (m *mockAliasMgr) GetPeerAlias(lnwire.ChannelID) (lnwire.ShortChannelID,
161161
}
162162

163163
func (m *mockAliasMgr) AddLocalAlias(lnwire.ShortChannelID,
164-
lnwire.ShortChannelID, bool) error {
164+
lnwire.ShortChannelID, bool, bool) error {
165165

166166
return nil
167167
}

htlcswitch/switch.go

Lines changed: 49 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2343,6 +2343,26 @@ func (s *Switch) addLiveLink(link ChannelLink) {
23432343
}
23442344
s.interfaceIndex[peerPub][link.ChanID()] = link
23452345

2346+
s.updateLinkAliases(link)
2347+
}
2348+
2349+
// UpdateLinkAliases is the externally exposed wrapper for updating link
2350+
// aliases. It acquires the indexMtx and calls the internal method.
2351+
func (s *Switch) UpdateLinkAliases(link ChannelLink) {
2352+
s.indexMtx.Lock()
2353+
defer s.indexMtx.Unlock()
2354+
2355+
s.updateLinkAliases(link)
2356+
}
2357+
2358+
// updateLinkAliases updates the aliases for a given link. This will cause the
2359+
// htlcswitch to consult the alias manager on the up to date values of its
2360+
// alias maps.
2361+
//
2362+
// NOTE: this MUST be called with the indexMtx held.
2363+
func (s *Switch) updateLinkAliases(link ChannelLink) {
2364+
linkScid := link.ShortChanID()
2365+
23462366
aliases := link.getAliases()
23472367
if link.isZeroConf() {
23482368
if link.zeroConfConfirmed() {
@@ -2367,6 +2387,21 @@ func (s *Switch) addLiveLink(link ChannelLink) {
23672387
s.baseIndex[alias] = linkScid
23682388
}
23692389
} else if link.negotiatedAliasFeature() {
2390+
// First, we flush any alias mappings for this link's scid
2391+
// before we populate the map again, in order to get rid of old
2392+
// values that no longer exist.
2393+
for alias, real := range s.aliasToReal {
2394+
if real == linkScid {
2395+
delete(s.aliasToReal, alias)
2396+
}
2397+
}
2398+
2399+
for alias, real := range s.baseIndex {
2400+
if real == linkScid {
2401+
delete(s.baseIndex, alias)
2402+
}
2403+
}
2404+
23702405
// The link's SCID is the confirmed SCID for non-zero-conf
23712406
// option-scid-alias feature bit channels.
23722407
for _, alias := range aliases {
@@ -2464,11 +2499,16 @@ func (s *Switch) getLinkByMapping(pkt *htlcPacket) (ChannelLink, error) {
24642499
chanID := pkt.outgoingChanID
24652500
aliasID := s.cfg.IsAlias(chanID)
24662501

2502+
// Custom alias mappings (that aren't communicated over the wire) are
2503+
// allowed to be outside the range of allowed SCID aliases (so they
2504+
// return false for IsAlias()).
2505+
_, haveAliasMapping := s.aliasToReal[chanID]
2506+
24672507
// Set the originalOutgoingChanID so the proper channel_update can be
24682508
// sent back if the option-scid-alias feature bit was negotiated.
24692509
pkt.originalOutgoingChanID = chanID
24702510

2471-
if aliasID {
2511+
if aliasID || haveAliasMapping {
24722512
// Since outgoingChanID is an alias, we'll fetch the link via
24732513
// baseIndex.
24742514
baseScid, ok := s.baseIndex[chanID]
@@ -2858,14 +2898,21 @@ func (s *Switch) failMailboxUpdate(outgoingScid,
28582898
// the associated channel is not one of these, this function will return nil
28592899
// and the caller is expected to handle this properly. In this case, a return
28602900
// to the original non-alias behavior is expected.
2901+
//
2902+
//nolint:nestif
28612903
func (s *Switch) failAliasUpdate(scid lnwire.ShortChannelID,
28622904
incoming bool) *lnwire.ChannelUpdate {
28632905

28642906
// This function does not defer the unlocking because of the database
28652907
// lookups for ChannelUpdate.
28662908
s.indexMtx.RLock()
28672909

2868-
if s.cfg.IsAlias(scid) {
2910+
// Custom alias mappings (that aren't communicated over the wire) are
2911+
// allowed to be outside the range of allowed SCID aliases (so they
2912+
// return false for IsAlias()).
2913+
_, haveAliasMapping := s.aliasToReal[scid]
2914+
2915+
if s.cfg.IsAlias(scid) || haveAliasMapping {
28692916
// The alias SCID was used. In the incoming case this means
28702917
// the channel is zero-conf as the link sets the scid. In the
28712918
// outgoing case, the sender set the scid to use and may be

peer/brontide.go

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -357,7 +357,7 @@ type Config struct {
357357

358358
// AddLocalAlias persists an alias to an underlying alias store.
359359
AddLocalAlias func(alias, base lnwire.ShortChannelID,
360-
gossip bool) error
360+
gossip, liveUpdate bool) error
361361

362362
// AuxLeafStore is an optional store that can be used to store auxiliary
363363
// leaves for certain custom channel types.
@@ -838,6 +838,7 @@ func (p *Brontide) loadActiveChannels(chans []*channeldb.OpenChannel) (
838838

839839
err = p.cfg.AddLocalAlias(
840840
aliasScid, dbChan.ShortChanID(), false,
841+
false,
841842
)
842843
if err != nil {
843844
return nil, err

server.go

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -639,7 +639,18 @@ func newServer(cfg *Config, listenAddrs []net.Addr,
639639
thresholdSats := btcutil.Amount(cfg.DustThreshold)
640640
thresholdMSats := lnwire.NewMSatFromSatoshis(thresholdSats)
641641

642-
s.aliasMgr, err = aliasmgr.NewManager(dbs.ChanStateDB)
642+
linkUpdater := func(shortID lnwire.ShortChannelID) error {
643+
link, err := s.htlcSwitch.GetLinkByShortID(shortID)
644+
if err != nil {
645+
return err
646+
}
647+
648+
s.htlcSwitch.UpdateLinkAliases(link)
649+
650+
return nil
651+
}
652+
653+
s.aliasMgr, err = aliasmgr.NewManager(dbs.ChanStateDB, linkUpdater)
643654
if err != nil {
644655
return nil, err
645656
}

0 commit comments

Comments
 (0)