From 1c8d835499f6566215c0f03e9142fdf0a8a14406 Mon Sep 17 00:00:00 2001 From: George Tsagkarelis Date: Tue, 9 Dec 2025 14:10:19 +0100 Subject: [PATCH 1/2] rfq+lndservices: remove scid alias of expired quotes We use the new LND RPC endpoint that looks up the base scid for an alias, in order to use it to delete the mapping shortly after. This is important to avoid tail emission of stale quote in LND's storage. --- lndservices/router_client.go | 7 ++++++ rfq/manager.go | 7 ++++++ rfq/order.go | 46 ++++++++++++++++++++++++++++++++---- 3 files changed, 55 insertions(+), 5 deletions(-) diff --git a/lndservices/router_client.go b/lndservices/router_client.go index 572bf1445..0969ca188 100644 --- a/lndservices/router_client.go +++ b/lndservices/router_client.go @@ -45,6 +45,13 @@ func (l *LndRouterClient) DeleteLocalAlias(ctx context.Context, alias, return l.lnd.Router.XDeleteLocalChanAlias(ctx, alias, baseScid) } +// FetchBaseAlias finds the base channel ID for a given alias. +func (l *LndRouterClient) FetchBaseAlias(ctx context.Context, + alias lnwire.ShortChannelID) (lnwire.ShortChannelID, error) { + + return l.lnd.Router.XFindBaseLocalChanAlias(ctx, alias) +} + // SubscribeHtlcEvents subscribes to a stream of events related to // HTLC updates. func (l *LndRouterClient) SubscribeHtlcEvents( diff --git a/rfq/manager.go b/rfq/manager.go index 04723e98a..90bd93f4d 100644 --- a/rfq/manager.go +++ b/rfq/manager.go @@ -63,6 +63,12 @@ type ScidAliasManager interface { // Manager's maps. DeleteLocalAlias(ctx context.Context, alias, baseScid lnwire.ShortChannelID) error + + // FetchBaseAlias finds the base channel ID for a given alias. This scid + // will correspond to the real channel scid that is used to identify the + // channel. + FetchBaseAlias(ctx context.Context, + alias lnwire.ShortChannelID) (lnwire.ShortChannelID, error) } type ( @@ -231,6 +237,7 @@ func (m *Manager) startSubsystems(ctx context.Context) error { CleanupInterval: CacheCleanupInterval, HtlcInterceptor: m.cfg.HtlcInterceptor, HtlcSubscriber: m.cfg.HtlcSubscriber, + AliasManager: m.cfg.AliasManager, AcceptHtlcEvents: m.acceptHtlcEvents, SpecifierChecker: m.AssetMatchesSpecifier, NoOpHTLCs: m.cfg.NoOpHTLCs, diff --git a/rfq/order.go b/rfq/order.go index 182a6e4af..9c9823c59 100644 --- a/rfq/order.go +++ b/rfq/order.go @@ -688,6 +688,10 @@ type OrderHandlerCfg struct { // intercept and accept/reject HTLCs. HtlcInterceptor HtlcInterceptor + // AliasManager is the SCID alias manager. This component is used to add + // and remove SCID aliases. + AliasManager ScidAliasManager + // AcceptHtlcEvents is a channel that receives accepted HTLCs. AcceptHtlcEvents chan<- *AcceptHtlcEvent @@ -1055,8 +1059,8 @@ func (h *OrderHandler) RegisterAssetSalePolicy( return nil } -// RegisterAssetPurchasePolicy generates and registers an asset buy policy with the -// order handler. This function takes an incoming sell accept message as an +// RegisterAssetPurchasePolicy generates and registers an asset buy policy with +// the order handler. This function takes an incoming sell accept message as an // argument. func (h *OrderHandler) RegisterAssetPurchasePolicy( sellAccept rfqmsg.SellAccept) error { @@ -1245,9 +1249,41 @@ func (h *OrderHandler) cleanupStalePolicies() { h.policies.ForEach( func(scid SerialisedScid, policy Policy) error { - if policy.HasExpired() { - staleCounter++ - h.policies.Delete(scid) + if !policy.HasExpired() { + return nil + } + + staleCounter++ + + // Delete the local entry of this policy. + h.policies.Delete(scid) + + ctx, cancel := h.WithCtxQuitCustomTimeout( + h.DefaultTimeout, + ) + defer cancel() + + aliasScid := lnwire.NewShortChanIDFromInt( + uint64(scid), + ) + + // Find the base SCID for the alias. + baseScid, err := h.cfg.AliasManager.FetchBaseAlias( + ctx, aliasScid, + ) + if err != nil { + log.Warnf("Error finding base SCID for alias "+ + "%d: %v", scid, err) + return nil + } + + // Delete the alias scid mapping on LND. + err = h.cfg.AliasManager.DeleteLocalAlias( + ctx, aliasScid, baseScid, + ) + if err != nil { + log.Warnf("Error deleting SCID alias %d: %v", + scid, err) } return nil From 38c4c7a9cfb4c3a51434572927053a58239fd238 Mon Sep 17 00:00:00 2001 From: George Tsagkarelis Date: Tue, 9 Dec 2025 14:11:58 +0100 Subject: [PATCH 2/2] rfq: dispatch order handler main loop in go routine We break the main event loop into its own goroutine, which was previously not running at all as the HTLC interceptor was a blocking call. --- rfq/order.go | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/rfq/order.go b/rfq/order.go index 9c9823c59..21417dfc5 100644 --- a/rfq/order.go +++ b/rfq/order.go @@ -968,7 +968,7 @@ func (h *OrderHandler) Start(ctx context.Context) error { return } - // Start the main event loop in a separate goroutine. + // Start the HTLC interceptor in a separate go routine. h.Wg.Add(1) go func() { defer h.Wg.Done() @@ -990,6 +990,12 @@ func (h *OrderHandler) Start(ctx context.Context) error { return } + }() + + // Start the main event loop in a separate go routine. + h.Wg.Add(1) + go func() { + defer h.Wg.Done() h.mainEventLoop() }()