multi: add omit_hops option to ListPayments RPC
What changed, and why it matters
This commit adds a new optional flag called omit_hops to the ListPayments RPC in the LND Lightning node. When enabled, the node skips loading detailed per-hop route information for each payment attempt, returning only summary route fields. This is a performance and data-reduction feature, not a security fix or vulnerability. There is no indication in the commit that it addresses a security issue.
No security action required. Review as a normal feature addition. Operators may choose to use omit_hops when large payment histories cause slow ListPayments responses.
Security signals we found
No strong security signals were identified.
Evidence from the diff
The change introduces an OmitHops boolean to ListPaymentsRequest, propagates it through the RPC, CLI, protobuf, swagger definitions, and the payments database query layer. In the SQL store, when OmitHops is true, the code avoids executing batch queries for hops, hop custom records, and route custom records, and constructs a route.Route with Hops=nil while preserving TotalTimeLock, TotalAmount, SourcePubKey, and FirstHopAmount. Existing callers that do not set the flag continue to receive full hop data. No security boundary is crossed, no input is trusted differently, and no vulnerability is patched.
Changed components
lnrpc/lightning.protolnrpc/lightning.pb.golnrpc/lightning.swagger.jsoncmd/commands/cmd_payments.gopayments/db/query.gopayments/db/sql_converters.gopayments/db/sql_converters_test.gopayments/db/sql_store.gorpcserver.goInspect captured patch +354 / −37
diff --git a/cmd/commands/cmd_payments.go b/cmd/commands/cmd_payments.go
index d13b52d..9e46d36 100644
--- a/cmd/commands/cmd_payments.go
+++ b/cmd/commands/cmd_payments.go
@@ -1497,6 +1497,11 @@ var listPaymentsCommand = cli.Command{
"payments with creation date less than or " +
"equal to it",
},
+ cli.BoolFlag{
+ Name: "omit_hops",
+ Usage: "if set, omit hop-level route data to " +
+ "reduce query cost and response size",
+ },
},
Action: actionDecorator(listPayments),
}
@@ -1514,6 +1519,7 @@ func listPayments(ctx *cli.Context) error {
CountTotalPayments: ctx.Bool("count_total_payments"),
CreationDateStart: ctx.Uint64("creation_date_start"),
CreationDateEnd: ctx.Uint64("creation_date_end"),
+ OmitHops: ctx.Bool("omit_hops"),
}
payments, err := client.ListPayments(ctxc, req)
diff --git a/lnrpc/lightning.pb.go b/lnrpc/lightning.pb.go
index 5f97bbd..d987f75 100644
--- a/lnrpc/lightning.pb.go
+++ b/lnrpc/lightning.pb.go
@@ -14277,8 +14277,11 @@ type ListPaymentsRequest struct {
// If set, returns all payments with a creation date less than or equal to
// it. Measured in seconds since the unix epoch.
CreationDateEnd uint64 `protobuf:"varint,7,opt,name=creation_date_end,json=creationDateEnd,proto3" json:"creation_date_end,omitempty"`
- unknownFields protoimpl.UnknownFields
- sizeCache protoimpl.SizeCache
+ // If set, omit hop-level route data for HTLC attempts to reduce query
+ // cost and response size.
+ OmitHops bool `protobuf:"varint,8,opt,name=omit_hops,json=omitHops,proto3" json:"omit_hops,omitempty"`
+ unknownFields protoimpl.UnknownFields
+ sizeCache protoimpl.SizeCache
}
func (x *ListPaymentsRequest) Reset() {
@@ -14360,6 +14363,13 @@ func (x *ListPaymentsRequest) GetCreationDateEnd() uint64 {
return 0
}
+func (x *ListPaymentsRequest) GetOmitHops() bool {
+ if x != nil {
+ return x.OmitHops
+ }
+ return false
+}
+
type ListPaymentsResponse struct {
state protoimpl.MessageState `protogen:"open.v1"`
// The list of payments
@@ -19922,7 +19932,7 @@ const file_lightning_proto_rawDesc = "" +
"\tIN_FLIGHT\x10\x00\x12\r\n" +
"\tSUCCEEDED\x10\x01\x12\n" +
"\n" +
- "\x06FAILED\x10\x02\"\xb4\x02\n" +
+ "\x06FAILED\x10\x02\"\xd1\x02\n" +
"\x13ListPaymentsRequest\x12-\n" +
"\x12include_incomplete\x18\x01 \x01(\bR\x11includeIncomplete\x12!\n" +
"\findex_offset\x18\x02 \x01(\x04R\vindexOffset\x12!\n" +
@@ -19930,7 +19940,8 @@ const file_lightning_proto_rawDesc = "" +
"\breversed\x18\x04 \x01(\bR\breversed\x120\n" +
"\x14count_total_payments\x18\x05 \x01(\bR\x12countTotalPayments\x12.\n" +
"\x13creation_date_start\x18\x06 \x01(\x04R\x11creationDateStart\x12*\n" +
- "\x11creation_date_end\x18\a \x01(\x04R\x0fcreationDateEnd\"\xca\x01\n" +
+ "\x11creation_date_end\x18\a \x01(\x04R\x0fcreationDateEnd\x12\x1b\n" +
+ "\tomit_hops\x18\b \x01(\bR\bomitHops\"\xca\x01\n" +
"\x14ListPaymentsResponse\x12*\n" +
"\bpayments\x18\x01 \x03(\v2\x0e.lnrpc.PaymentR\bpayments\x12,\n" +
"\x12first_index_offset\x18\x02 \x01(\x04R\x10firstIndexOffset\x12*\n" +
diff --git a/lnrpc/lightning.proto b/lnrpc/lightning.proto
index 66dedd4..b1323db 100644
--- a/lnrpc/lightning.proto
+++ b/lnrpc/lightning.proto
@@ -4554,6 +4554,10 @@ message ListPaymentsRequest {
// If set, returns all payments with a creation date less than or equal to
// it. Measured in seconds since the unix epoch.
uint64 creation_date_end = 7;
+
+ // If set, omit hop-level route data for HTLC attempts to reduce query
+ // cost and response size.
+ bool omit_hops = 8;
}
message ListPaymentsResponse {
diff --git a/lnrpc/lightning.swagger.json b/lnrpc/lightning.swagger.json
index bc16701..96ded86 100644
--- a/lnrpc/lightning.swagger.json
+++ b/lnrpc/lightning.swagger.json
@@ -2449,6 +2449,13 @@
"required": false,
"type": "string",
"format": "uint64"
+ },
+ {
+ "name": "omit_hops",
+ "description": "If set, omit hop-level route data for HTLC attempts to reduce query\ncost and response size.",
+ "in": "query",
+ "required": false,
+ "type": "boolean"
}
],
"tags": [
diff --git a/payments/db/query.go b/payments/db/query.go
index 40dfd43..a45b10a 100644
--- a/payments/db/query.go
+++ b/payments/db/query.go
@@ -44,6 +44,10 @@ type Query struct {
// CreationDateEnd, expressed in Unix seconds, if set, filters out all
// payments with a creation date less than or equal to it.
CreationDateEnd int64
+
+ // OmitHops skips loading hop and hop-level custom record data for
+ // HTLC attempts when set to true.
+ OmitHops bool
}
// Response contains the result of a query to the payments database.
diff --git a/payments/db/sql_converters.go b/payments/db/sql_converters.go
index 66f3b1d..7e19e33 100644
--- a/payments/db/sql_converters.go
+++ b/payments/db/sql_converters.go
@@ -41,12 +41,13 @@ func dbPaymentToCreationInfo(paymentIdentifier []byte, amountMsat int64,
func dbAttemptToHTLCAttempt(dbAttempt sqlc.FetchHtlcAttemptsForPaymentsRow,
hops []sqlc.FetchHopsForAttemptsRow,
hopCustomRecords map[int64][]sqlc.PaymentHopCustomRecord,
- routeCustomRecords []sqlc.PaymentAttemptFirstHopCustomRecord) (
+ routeCustomRecords []sqlc.PaymentAttemptFirstHopCustomRecord,
+ includeHops bool) (
*HTLCAttempt, error) {
// Convert route-level first hop custom records to CustomRecords map.
var firstHopWireCustomRecords lnwire.CustomRecords
- if len(routeCustomRecords) > 0 {
+ if includeHops && len(routeCustomRecords) > 0 {
firstHopWireCustomRecords = make(lnwire.CustomRecords)
for _, record := range routeCustomRecords {
firstHopWireCustomRecords[uint64(record.Key)] =
@@ -59,6 +60,7 @@ func dbAttemptToHTLCAttempt(dbAttempt sqlc.FetchHtlcAttemptsForPaymentsRow,
hops, hopCustomRecords, dbAttempt.FirstHopAmountMsat,
dbAttempt.RouteTotalTimeLock, dbAttempt.RouteTotalAmount,
dbAttempt.RouteSourceKey, firstHopWireCustomRecords,
+ !includeHops,
)
if err != nil {
return nil, fmt.Errorf("failed to convert to route: %w",
@@ -148,11 +150,37 @@ func dbAttemptToHTLCAttempt(dbAttempt sqlc.FetchHtlcAttemptsForPaymentsRow,
func dbDataToRoute(hops []sqlc.FetchHopsForAttemptsRow,
hopCustomRecords map[int64][]sqlc.PaymentHopCustomRecord,
firstHopAmountMsat int64, totalTimeLock int32, totalAmount int64,
- sourceKey []byte, firstHopWireCustomRecords lnwire.CustomRecords) (
+ sourceKey []byte, firstHopWireCustomRecords lnwire.CustomRecords,
+ allowEmpty bool) (
*route.Route, error) {
if len(hops) == 0 {
- return nil, fmt.Errorf("no hops provided")
+ if !allowEmpty {
+ return nil, fmt.Errorf("no hops provided")
+ }
+
+ var sourceNode route.Vertex
+ copy(sourceNode[:], sourceKey)
+
+ route := &route.Route{
+ TotalTimeLock: uint32(totalTimeLock),
+ TotalAmount: lnwire.MilliSatoshi(
+ totalAmount,
+ ),
+ SourcePubKey: sourceNode,
+ Hops: nil,
+ FirstHopWireCustomRecords: firstHopWireCustomRecords,
+ }
+
+ if firstHopAmountMsat != 0 {
+ route.FirstHopAmount = tlv.NewRecordT[tlv.TlvType0](
+ tlv.NewBigSizeT(lnwire.MilliSatoshi(
+ firstHopAmountMsat,
+ )),
+ )
+ }
+
+ return route, nil
}
// Hops are already sorted by hop_index from the SQL query.
diff --git a/payments/db/sql_converters_test.go b/payments/db/sql_converters_test.go
new file mode 100644
index 0000000..e28da1e
--- /dev/null
+++ b/payments/db/sql_converters_test.go
@@ -0,0 +1,246 @@
+//go:build test_db_sqlite || test_db_postgres
+
+package paymentsdb
+
+import (
+ "database/sql"
+ "testing"
+ "time"
+
+ "github.com/lightningnetwork/lnd/lntypes"
+ "github.com/lightningnetwork/lnd/lnwire"
+ "github.com/lightningnetwork/lnd/record"
+ "github.com/lightningnetwork/lnd/sqldb/sqlc"
+ "github.com/stretchr/testify/require"
+)
+
+// TestOmitHopsRouteBuilding tests the omit_hops behavior in dbDataToRoute.
+// When allowEmpty is true (omit_hops=true) and no hops are provided, a minimal
+// route with only route-level fields should be returned. When allowEmpty is
+// false, the same scenario should return an error.
+func TestOmitHopsRouteBuilding(t *testing.T) {
+ t.Parallel()
+
+ sourceKey := vertex[:]
+
+ // With allowEmpty=true (omit_hops), empty hops should return a
+ // minimal route preserving route-level fields.
+ t.Run("omit hops returns minimal route", func(t *testing.T) {
+ t.Parallel()
+
+ r, err := dbDataToRoute(
+ nil, nil, 0, 123, 1000, sourceKey, nil, true,
+ )
+ require.NoError(t, err)
+ require.Nil(t, r.Hops)
+ require.Equal(t, uint32(123), r.TotalTimeLock)
+ require.Equal(t, lnwire.MilliSatoshi(1000), r.TotalAmount)
+ require.Equal(t, vertex, r.SourcePubKey)
+ })
+
+ // With allowEmpty=false (include hops), empty hops should error.
+ t.Run("include hops errors on empty hops", func(t *testing.T) {
+ t.Parallel()
+
+ _, err := dbDataToRoute(
+ nil, nil, 0, 123, 1000, sourceKey, nil, false,
+ )
+ require.Error(t, err)
+ })
+}
+
+// TestOmitHopsAttemptConversion tests that dbAttemptToHTLCAttempt correctly
+// handles the includeHops flag. When false, route custom records should be
+// skipped and the route should have no hops. When true, hops and custom
+// records should be fully populated.
+func TestOmitHopsAttemptConversion(t *testing.T) {
+ t.Parallel()
+
+ var paymentHash lntypes.Hash
+ copy(paymentHash[:], testHash[:])
+
+ sessionKey := genSessionKey(t)
+ var sessionKeyBytes [32]byte
+ copy(sessionKeyBytes[:], sessionKey.Serialize())
+
+ baseAttempt := sqlc.FetchHtlcAttemptsForPaymentsRow{
+ ID: 1,
+ AttemptIndex: 1,
+ PaymentID: 1,
+ SessionKey: sessionKeyBytes[:],
+ AttemptTime: time.Now(),
+ PaymentHash: paymentHash[:],
+ RouteTotalTimeLock: 123,
+ RouteTotalAmount: 1000,
+ RouteSourceKey: vertex[:],
+ }
+
+ hops := []sqlc.FetchHopsForAttemptsRow{
+ {
+ ID: 10,
+ HtlcAttemptIndex: 1,
+ HopIndex: 0,
+ PubKey: vertex[:],
+ Scid: "12345",
+ OutgoingTimeLock: 111,
+ AmtToForward: 555,
+ },
+ }
+
+ hopCustomRecords := map[int64][]sqlc.PaymentHopCustomRecord{
+ 10: {{ID: 1, HopID: 10, Key: 65536, Value: []byte("val")}},
+ }
+
+ routeCustomRecords := []sqlc.PaymentAttemptFirstHopCustomRecord{
+ {ID: 1, HtlcAttemptIndex: 1, Key: 65537, Value: []byte("rcr")},
+ }
+
+ t.Run("include hops populates route fully", func(t *testing.T) {
+ t.Parallel()
+
+ attempt, err := dbAttemptToHTLCAttempt(
+ baseAttempt, hops, hopCustomRecords,
+ routeCustomRecords, true,
+ )
+ require.NoError(t, err)
+ require.Len(t, attempt.Route.Hops, 1)
+ require.Equal(t, uint64(12345),
+ attempt.Route.Hops[0].ChannelID)
+ require.Equal(t,
+ record.CustomSet{65536: []byte("val")},
+ attempt.Route.Hops[0].CustomRecords,
+ )
+ require.Equal(t,
+ lnwire.CustomRecords{65537: []byte("rcr")},
+ attempt.Route.FirstHopWireCustomRecords,
+ )
+ })
+
+ t.Run("omit hops skips route data", func(t *testing.T) {
+ t.Parallel()
+
+ attempt, err := dbAttemptToHTLCAttempt(
+ baseAttempt, nil, nil,
+ routeCustomRecords, false,
+ )
+ require.NoError(t, err)
+ require.Nil(t, attempt.Route.Hops)
+ require.Nil(t, attempt.Route.FirstHopWireCustomRecords)
+ require.Equal(t, uint32(123), attempt.Route.TotalTimeLock)
+ require.Equal(t, lnwire.MilliSatoshi(1000),
+ attempt.Route.TotalAmount)
+ })
+}
+
+// TestOmitHopsBuildPayment tests that buildPaymentFromBatchData passes the
+// includeHops flag correctly, producing payments with or without hop data
+// while preserving payment-level information in both cases.
+func TestOmitHopsBuildPayment(t *testing.T) {
+ t.Parallel()
+
+ var paymentHash lntypes.Hash
+ copy(paymentHash[:], testHash[:])
+
+ sessionKey := genSessionKey(t)
+ var sessionKeyBytes [32]byte
+ copy(sessionKeyBytes[:], sessionKey.Serialize())
+
+ now := time.Now().Truncate(time.Second)
+
+ dbPayment := sqlc.FilterPaymentsRow{
+ Payment: sqlc.Payment{
+ ID: 1,
+ PaymentIdentifier: paymentHash[:],
+ AmountMsat: 1000,
+ CreatedAt: now.UTC(),
+ },
+ IntentPayload: []byte("test_payload"),
+ }
+
+ attemptRow := sqlc.FetchHtlcAttemptsForPaymentsRow{
+ ID: 1,
+ AttemptIndex: 10,
+ PaymentID: 1,
+ SessionKey: sessionKeyBytes[:],
+ AttemptTime: now,
+ PaymentHash: paymentHash[:],
+ RouteTotalTimeLock: 123,
+ RouteTotalAmount: 1000,
+ RouteSourceKey: vertex[:],
+ ResolutionType: sql.NullInt32{
+ Int32: int32(HTLCAttemptResolutionSettled),
+ Valid: true,
+ },
+ ResolutionTime: sql.NullTime{
+ Time: now, Valid: true,
+ },
+ SettlePreimage: rev[:],
+ }
+
+ hopRow := sqlc.FetchHopsForAttemptsRow{
+ ID: 100, HtlcAttemptIndex: 10, HopIndex: 0,
+ PubKey: vertex[:], Scid: "12345",
+ OutgoingTimeLock: 111, AmtToForward: 555,
+ }
+
+ makeBatchData := func(
+ withHops bool) *paymentsDetailsData {
+
+ //nolint:ll
+ bd := &paymentsDetailsData{
+ paymentCustomRecords: make(
+ map[int64][]sqlc.PaymentFirstHopCustomRecord,
+ ),
+ attempts: map[int64][]sqlc.FetchHtlcAttemptsForPaymentsRow{
+ 1: {attemptRow},
+ },
+ hopsByAttempt: make(
+ map[int64][]sqlc.FetchHopsForAttemptsRow,
+ ),
+ hopCustomRecords: make(
+ map[int64][]sqlc.PaymentHopCustomRecord,
+ ),
+ routeCustomRecords: make(
+ map[int64][]sqlc.PaymentAttemptFirstHopCustomRecord,
+ ),
+ }
+ if withHops {
+ bd.hopsByAttempt[10] = []sqlc.FetchHopsForAttemptsRow{
+ hopRow,
+ }
+ }
+
+ return bd
+ }
+
+ t.Run("include hops builds full payment", func(t *testing.T) {
+ t.Parallel()
+
+ mp, err := buildPaymentFromBatchData(
+ dbPayment, makeBatchData(true), true,
+ )
+ require.NoError(t, err)
+ require.Len(t, mp.HTLCs, 1)
+ require.Len(t, mp.HTLCs[0].Route.Hops, 1)
+ require.Equal(t, paymentHash, mp.Info.PaymentIdentifier)
+ require.NotNil(t, mp.HTLCs[0].Settle)
+ })
+
+ t.Run("omit hops preserves payment info without route data",
+ func(t *testing.T) {
+ t.Parallel()
+
+ mp, err := buildPaymentFromBatchData(
+ dbPayment, makeBatchData(false), false,
+ )
+ require.NoError(t, err)
+ require.Len(t, mp.HTLCs, 1)
+ require.Nil(t, mp.HTLCs[0].Route.Hops)
+ require.Equal(t, paymentHash,
+ mp.Info.PaymentIdentifier)
+ require.Equal(t, lnwire.MilliSatoshi(1000),
+ mp.Info.Value)
+ require.NotNil(t, mp.HTLCs[0].Settle)
+ },
+ )
+}
diff --git a/payments/db/sql_store.go b/payments/db/sql_store.go
index 1c8ffb5..f7cdaa9 100644
--- a/payments/db/sql_store.go
+++ b/payments/db/sql_store.go
@@ -171,14 +171,14 @@ func fetchPaymentWithCompleteData(ctx context.Context,
// Load batch data for this single payment.
batchData, err := batchLoadPaymentDetailsData(
- ctx, cfg, db, []int64{payment.ID},
+ ctx, cfg, db, []int64{payment.ID}, true,
)
if err != nil {
return nil, fmt.Errorf("failed to load batch data: %w", err)
}
// Build the payment from the batch data.
- return buildPaymentFromBatchData(dbPayment, batchData)
+ return buildPaymentFromBatchData(dbPayment, batchData, true)
}
// paymentsCompleteData holds the full payment data when batch loading base
@@ -198,7 +198,9 @@ func batchLoadPayments(ctx context.Context, cfg *sqldb.QueryConfig,
err)
}
- batchData, err := batchLoadPaymentDetailsData(ctx, cfg, db, paymentIDs)
+ batchData, err := batchLoadPaymentDetailsData(
+ ctx, cfg, db, paymentIDs, true,
+ )
if err != nil {
return nil, fmt.Errorf("failed to load payment batch data: %w",
err)
@@ -568,7 +570,8 @@ func computePaymentStatusFromResolutions(resolutionTypes []sql.NullInt32,
// batchLoadPaymentDetailsData loads all related data for multiple payments in
// batch. It uses a batch queries to fetch all data for the given payment IDs.
func batchLoadPaymentDetailsData(ctx context.Context, cfg *sqldb.QueryConfig,
- db SQLQueries, paymentIDs []int64) (*paymentsDetailsData, error) {
+ db SQLQueries, paymentIDs []int64, includeHops bool) (
+ *paymentsDetailsData, error) {
batchData := &paymentsDetailsData{
paymentCustomRecords: make(
@@ -615,31 +618,35 @@ func batchLoadPaymentDetailsData(ctx context.Context, cfg *sqldb.QueryConfig,
return batchData, nil
}
- // Load hops for all attempts and collect hop IDs.
- hopIDs, err := batchLoadHopsForAttempts(
- ctx, cfg, db, allAttemptIndices, batchData,
- )
- if err != nil {
- return nil, fmt.Errorf("failed to fetch hops for attempts: %w",
- err)
- }
-
- // Load hop-level custom records if there are any hops.
- if len(hopIDs) > 0 {
- err = batchLoadHopCustomRecords(ctx, cfg, db, hopIDs, batchData)
+ if includeHops {
+ // Load hops for all attempts and collect hop IDs.
+ hopIDs, err := batchLoadHopsForAttempts(
+ ctx, cfg, db, allAttemptIndices, batchData,
+ )
if err != nil {
- return nil, fmt.Errorf("failed to fetch hop custom "+
- "records: %w", err)
+ return nil, fmt.Errorf("failed to fetch hops "+
+ "for attempts: %w", err)
}
- }
- // Load route-level first hop custom records.
- err = batchLoadRouteCustomRecords(
- ctx, cfg, db, allAttemptIndices, batchData,
- )
- if err != nil {
- return nil, fmt.Errorf("failed to fetch route custom "+
- "records: %w", err)
+ // Load hop-level custom records if there are any hops.
+ if len(hopIDs) > 0 {
+ err = batchLoadHopCustomRecords(
+ ctx, cfg, db, hopIDs, batchData,
+ )
+ if err != nil {
+ return nil, fmt.Errorf("failed to fetch "+
+ "hop custom records: %w", err)
+ }
+ }
+
+ // Load route-level first hop custom records.
+ err = batchLoadRouteCustomRecords(
+ ctx, cfg, db, allAttemptIndices, batchData,
+ )
+ if err != nil {
+ return nil, fmt.Errorf("failed to fetch route "+
+ "custom records: %w", err)
+ }
}
return batchData, nil
@@ -648,7 +655,8 @@ func batchLoadPaymentDetailsData(ctx context.Context, cfg *sqldb.QueryConfig,
// buildPaymentFromBatchData builds a complete MPPayment from a database payment
// and pre-loaded batch data.
func buildPaymentFromBatchData(dbPayment sqlc.PaymentAndIntent,
- batchData *paymentsDetailsData) (*MPPayment, error) {
+ batchData *paymentsDetailsData, includeHops bool) (
+ *MPPayment, error) {
// The query will only return BOLT 11 payment intents or intents with
// no intent type set.
@@ -688,6 +696,7 @@ func buildPaymentFromBatchData(dbPayment sqlc.PaymentAndIntent,
dbAttempt, batchData.hopsByAttempt[attemptIndex],
batchData.hopCustomRecords,
batchData.routeCustomRecords[attemptIndex],
+ includeHops,
)
if err != nil {
return nil, fmt.Errorf("failed to convert attempt "+
@@ -786,6 +795,7 @@ func (s *SQLStore) QueryPayments(ctx context.Context, query Query) (Response,
return batchLoadPaymentDetailsData(
ctx, s.cfg.QueryCfg, db, paymentIDs,
+ !query.OmitHops,
)
}
@@ -797,7 +807,7 @@ func (s *SQLStore) QueryPayments(ctx context.Context, query Query) (Response,
// Build the payment from the pre-loaded batch data.
mpPayment, err := buildPaymentFromBatchData(
- dbPayment, batchData,
+ dbPayment, batchData, !query.OmitHops,
)
if err != nil {
return fmt.Errorf("failed to fetch payment "+
@@ -1051,7 +1061,7 @@ func (s *SQLStore) FetchInFlightPayments(ctx context.Context) ([]*MPPayment,
// Build the payment from batch data.
mpPayment, err := buildPaymentFromBatchData(
- dbPayment, batchData.paymentsDetailsData,
+ dbPayment, batchData.paymentsDetailsData, true,
)
if err != nil {
return fmt.Errorf("failed to build payment: %w",
diff --git a/rpcserver.go b/rpcserver.go
index 84e2afa..401f33d 100644
--- a/rpcserver.go
+++ b/rpcserver.go
@@ -7668,6 +7668,7 @@ func (r *rpcServer) ListPayments(ctx context.Context,
CountTotal: req.CountTotalPayments,
CreationDateStart: int64(req.CreationDateStart),
CreationDateEnd: int64(req.CreationDateEnd),
+ OmitHops: req.OmitHops,
}
// If the maximum number of payments wasn't specified, we default to
Why this scored 19/100
Community notes
Notes can correct, qualify, or add evidence to the AI analysis. Every note shown here has been validated by a human moderator.
The AI analysis stands alone for now. Submit a note if you can add evidence or important context.