loop: omit payment hops in cost migration

The cost cleanup migration pages through LND payments only to build
a payment-hash to fee map. It does not inspect HTLC attempts,
routes, or per-hop data; pagination still uses the top-level index
offsets returned by ListPayments.

Setting OmitHops is safe for this migration because LND only strips
hop-level route data from HTLC attempts, while preserving the top-level
payment fields the migration reads: hash, fee, and response offsets.
This reduces response size and query cost for nodes with many or large
MPP payments without changing the calculated swap costs.

The migration test records the mocked ListPayments requests and asserts
that OmitHops is set.
This commit is contained in:
Boris Nagaev 2026-06-20 16:24:35 -05:00
parent 09c92527ea
commit d324b4bfd8
No known key found for this signature in database
4 changed files with 34 additions and 7 deletions

View file

@ -266,6 +266,11 @@ func (h *mockLightningClient) ListPayments(_ context.Context,
req lndclient.ListPaymentsRequest) (*lndclient.ListPaymentsResponse,
error) {
h.lnd.lock.Lock()
defer h.lnd.lock.Unlock()
h.lnd.ListPaymentsRequests = append(h.lnd.ListPaymentsRequests, req)
if req.Offset >= uint64(len(h.lnd.Payments)) {
return &lndclient.ListPaymentsResponse{}, nil
}
@ -273,7 +278,8 @@ func (h *mockLightningClient) ListPayments(_ context.Context,
lastIndexOffset := req.Offset + req.MaxPayments
lastIndexOffset = min(lastIndexOffset, uint64(len(h.lnd.Payments)))
result := h.lnd.Payments[req.Offset:lastIndexOffset]
result := make([]lndclient.Payment, lastIndexOffset-req.Offset)
copy(result, h.lnd.Payments[req.Offset:lastIndexOffset])
return &lndclient.ListPaymentsResponse{
Payments: result,

View file

@ -162,12 +162,13 @@ type LndMockServices struct {
// keyed by hash string.
Invoices map[lntypes.Hash]*lndclient.Invoice
Channels []lndclient.ChannelInfo
ChannelEdges map[uint64]*lndclient.ChannelEdge
ClosedChannels []lndclient.ClosedChannel
ForwardingEvents []lndclient.ForwardingEvent
Payments []lndclient.Payment
MissionControlState []lndclient.MissionControlEntry
Channels []lndclient.ChannelInfo
ChannelEdges map[uint64]*lndclient.ChannelEdge
ClosedChannels []lndclient.ClosedChannel
ForwardingEvents []lndclient.ForwardingEvent
Payments []lndclient.Payment
ListPaymentsRequests []lndclient.ListPaymentsRequest
MissionControlState []lndclient.MissionControlEntry
WaitForFinished func()
@ -185,6 +186,20 @@ func (s *LndMockServices) EpochSubscribers() int32 {
return int32(len(s.blockHeightListeners))
}
// ListPaymentsRequestsSnapshot returns a copy of all ListPayments requests
// recorded by the mock.
func (s *LndMockServices) ListPaymentsRequestsSnapshot() []lndclient.ListPaymentsRequest {
s.lock.Lock()
defer s.lock.Unlock()
requests := make(
[]lndclient.ListPaymentsRequest, len(s.ListPaymentsRequests),
)
copy(requests, s.ListPaymentsRequests)
return requests
}
// NotifyHeight notifies a new block height.
func (s *LndMockServices) NotifyHeight(height int32) error {
s.lock.Lock()