routing: pass BlindedPaymentPathSet around everywhere

Building on from the previous commit, here we pass the PathSet around
everywhere where we previously passed around the single BlindedPayment.
This commit is contained in:
Elle Mouton 2024-05-15 15:08:19 +02:00
parent 3d5f20b70f
commit 4a22ec8413
No known key found for this signature in database
GPG Key ID: D7D916376026F177
7 changed files with 94 additions and 92 deletions

View File

@ -388,10 +388,10 @@ func (r *RouterBackend) parseQueryRoutesRequest(in *lnrpc.QueryRoutesRequest) (
fromNode, toNode, amt, capacity, fromNode, toNode, amt, capacity,
) )
}, },
DestCustomRecords: record.CustomSet(in.DestCustomRecords), DestCustomRecords: record.CustomSet(in.DestCustomRecords),
CltvLimit: cltvLimit, CltvLimit: cltvLimit,
DestFeatures: destinationFeatures, DestFeatures: destinationFeatures,
BlindedPayment: blindedPathSet.GetPath(), BlindedPaymentPathSet: blindedPathSet,
} }
// Pass along an outgoing channel restriction if specified. // Pass along an outgoing channel restriction if specified.
@ -420,7 +420,7 @@ func (r *RouterBackend) parseQueryRoutesRequest(in *lnrpc.QueryRoutesRequest) (
return routing.NewRouteRequest( return routing.NewRouteRequest(
sourcePubKey, targetPubKey, amt, in.TimePref, restrictions, sourcePubKey, targetPubKey, amt, in.TimePref, restrictions,
customRecords, routeHintEdges, blindedPathSet.GetPath(), customRecords, routeHintEdges, blindedPathSet,
finalCLTVDelta, finalCLTVDelta,
) )
} }
@ -1007,7 +1007,7 @@ func (r *RouterBackend) extractIntentFromSendRequest(
if err != nil { if err != nil {
return nil, err return nil, err
} }
payIntent.BlindedPayment = pathSet.GetPath() payIntent.BlindedPathSet = pathSet
// Replace the target node with the target public key // Replace the target node with the target public key
// of the blinded path set. // of the blinded path set.

View File

@ -136,9 +136,8 @@ type finalHopParams struct {
// NOTE: If a non-nil blinded path is provided it is assumed to have been // NOTE: If a non-nil blinded path is provided it is assumed to have been
// validated by the caller. // validated by the caller.
func newRoute(sourceVertex route.Vertex, func newRoute(sourceVertex route.Vertex,
pathEdges []*unifiedEdge, currentHeight uint32, pathEdges []*unifiedEdge, currentHeight uint32, finalHop finalHopParams,
finalHop finalHopParams, blindedPath *sphinx.BlindedPath) ( blindedPathSet *BlindedPaymentPathSet) (*route.Route, error) {
*route.Route, error) {
var ( var (
hops []*route.Hop hops []*route.Hop
@ -153,8 +152,14 @@ func newRoute(sourceVertex route.Vertex,
// backwards below, this next hop gets closer and closer to the // backwards below, this next hop gets closer and closer to the
// sender of the payment. // sender of the payment.
nextIncomingAmount lnwire.MilliSatoshi nextIncomingAmount lnwire.MilliSatoshi
blindedPath *sphinx.BlindedPath
) )
if blindedPathSet != nil {
blindedPath = blindedPathSet.GetPath().BlindedPath
}
pathLength := len(pathEdges) pathLength := len(pathEdges)
for i := pathLength - 1; i >= 0; i-- { for i := pathLength - 1; i >= 0; i-- {
// Now we'll start to calculate the items within the per-hop // Now we'll start to calculate the items within the per-hop
@ -437,9 +442,9 @@ type RestrictParams struct {
// the payee. // the payee.
Metadata []byte Metadata []byte
// BlindedPayment is necessary to determine the hop size of the // BlindedPaymentPathSet is necessary to determine the hop size of the
// last/exit hop. // last/exit hop.
BlindedPayment *BlindedPayment BlindedPaymentPathSet *BlindedPaymentPathSet
} }
// PathFindingConfig defines global parameters that control the trade-off in // PathFindingConfig defines global parameters that control the trade-off in
@ -1365,9 +1370,11 @@ func getProbabilityBasedDist(weight int64, probability float64,
func lastHopPayloadSize(r *RestrictParams, finalHtlcExpiry int32, func lastHopPayloadSize(r *RestrictParams, finalHtlcExpiry int32,
amount lnwire.MilliSatoshi) uint64 { amount lnwire.MilliSatoshi) uint64 {
if r.BlindedPayment != nil { if r.BlindedPaymentPathSet != nil {
blindedPath := r.BlindedPayment.BlindedPath.BlindedHops paymentPath := r.BlindedPaymentPathSet.
blindedPoint := r.BlindedPayment.BlindedPath.BlindingPoint LargestLastHopPayloadPath()
blindedPath := paymentPath.BlindedPath.BlindedHops
blindedPoint := paymentPath.BlindedPath.BlindingPoint
encryptedData := blindedPath[len(blindedPath)-1].CipherText encryptedData := blindedPath[len(blindedPath)-1].CipherText
finalHop := route.Hop{ finalHop := route.Hop{

View File

@ -3277,6 +3277,11 @@ func TestBlindedRouteConstruction(t *testing.T) {
require.NoError(t, blindedPayment.Validate()) require.NoError(t, blindedPayment.Validate())
blindedPathSet, err := NewBlindedPaymentPathSet(
[]*BlindedPayment{blindedPayment},
)
require.NoError(t, err)
// Generate route hints from our blinded payment and a set of edges // Generate route hints from our blinded payment and a set of edges
// that make up the graph we'll give to route construction. The hints // that make up the graph we'll give to route construction. The hints
// map is keyed by source node, so we can retrieve our blinded edges // map is keyed by source node, so we can retrieve our blinded edges
@ -3382,7 +3387,7 @@ func TestBlindedRouteConstruction(t *testing.T) {
route, err := newRoute( route, err := newRoute(
sourceVertex, edges, currentHeight, finalHopParams, sourceVertex, edges, currentHeight, finalHopParams,
blindedPath, blindedPathSet,
) )
require.NoError(t, err) require.NoError(t, err)
require.Equal(t, expectedRoute, route) require.Equal(t, expectedRoute, route)
@ -3409,31 +3414,38 @@ func TestLastHopPayloadSize(t *testing.T) {
amtToForward = lnwire.MilliSatoshi(10000) amtToForward = lnwire.MilliSatoshi(10000)
finalHopExpiry int32 = 144 finalHopExpiry int32 = 144
oneHopBlindedPayment = &BlindedPayment{ oneHopPath = &sphinx.BlindedPath{
BlindedPath: &sphinx.BlindedPath{ BlindedHops: []*sphinx.BlindedHopInfo{
BlindedHops: []*sphinx.BlindedHopInfo{ {
{ CipherText: encrypedData,
CipherText: encrypedData,
},
}, },
BlindingPoint: blindedPoint,
}, },
BlindingPoint: blindedPoint,
} }
twoHopBlindedPayment = &BlindedPayment{
BlindedPath: &sphinx.BlindedPath{ twoHopPath = &sphinx.BlindedPath{
BlindedHops: []*sphinx.BlindedHopInfo{ BlindedHops: []*sphinx.BlindedHopInfo{
{ {
CipherText: encrypedData, CipherText: encrypedData,
}, },
{ {
CipherText: encrypedData, CipherText: encrypedData,
},
}, },
BlindingPoint: blindedPoint,
}, },
BlindingPoint: blindedPoint,
} }
) )
oneHopBlindedPayment, err := NewBlindedPaymentPathSet(
[]*BlindedPayment{{BlindedPath: oneHopPath}},
)
require.NoError(t, err)
twoHopBlindedPayment, err := NewBlindedPaymentPathSet(
[]*BlindedPayment{{BlindedPath: twoHopPath}},
)
require.NoError(t, err)
testCases := []struct { testCases := []struct {
name string name string
restrictions *RestrictParams restrictions *RestrictParams
@ -3454,7 +3466,7 @@ func TestLastHopPayloadSize(t *testing.T) {
{ {
name: "Blinded final hop introduction point", name: "Blinded final hop introduction point",
restrictions: &RestrictParams{ restrictions: &RestrictParams{
BlindedPayment: oneHopBlindedPayment, BlindedPaymentPathSet: oneHopBlindedPayment,
}, },
amount: amtToForward, amount: amtToForward,
finalHopExpiry: finalHopExpiry, finalHopExpiry: finalHopExpiry,
@ -3462,7 +3474,7 @@ func TestLastHopPayloadSize(t *testing.T) {
{ {
name: "Blinded final hop of a two hop payment", name: "Blinded final hop of a two hop payment",
restrictions: &RestrictParams{ restrictions: &RestrictParams{
BlindedPayment: twoHopBlindedPayment, BlindedPaymentPathSet: twoHopBlindedPayment,
}, },
amount: amtToForward, amount: amtToForward,
finalHopExpiry: finalHopExpiry, finalHopExpiry: finalHopExpiry,
@ -3490,12 +3502,11 @@ func TestLastHopPayloadSize(t *testing.T) {
} }
var finalHop route.Hop var finalHop route.Hop
if tc.restrictions.BlindedPayment != nil { if tc.restrictions.BlindedPaymentPathSet != nil {
blindedPath := tc.restrictions.BlindedPayment. path := tc.restrictions.BlindedPaymentPathSet.
BlindedPath.BlindedHops LargestLastHopPayloadPath()
blindedPath := path.BlindedPath.BlindedHops
blindedPoint := tc.restrictions.BlindedPayment. blindedPoint := path.BlindedPath.BlindingPoint
BlindedPath.BlindingPoint
//nolint:lll //nolint:lll
finalHop = route.Hop{ finalHop = route.Hop{

View File

@ -5,7 +5,6 @@ import (
"github.com/btcsuite/btcd/btcec/v2" "github.com/btcsuite/btcd/btcec/v2"
"github.com/btcsuite/btclog" "github.com/btcsuite/btclog"
sphinx "github.com/lightningnetwork/lightning-onion"
"github.com/lightningnetwork/lnd/build" "github.com/lightningnetwork/lnd/build"
"github.com/lightningnetwork/lnd/channeldb" "github.com/lightningnetwork/lnd/channeldb"
"github.com/lightningnetwork/lnd/channeldb/models" "github.com/lightningnetwork/lnd/channeldb/models"
@ -206,13 +205,13 @@ func newPaymentSession(p *LightningPayment, selfNode route.Vertex,
return nil, err return nil, err
} }
if p.BlindedPayment != nil { if p.BlindedPathSet != nil {
if len(edges) != 0 { if len(edges) != 0 {
return nil, fmt.Errorf("cannot have both route hints " + return nil, fmt.Errorf("cannot have both route hints " +
"and blinded path") "and blinded path")
} }
edges, err = p.BlindedPayment.toRouteHints() edges, err = p.BlindedPathSet.ToRouteHints()
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -342,7 +341,7 @@ func (p *paymentSession) RequestRoute(maxAmt, feeLimit lnwire.MilliSatoshi,
// can split. Split payments to blinded paths won't have // can split. Split payments to blinded paths won't have
// MPP records. // MPP records.
if p.payment.PaymentAddr == nil && if p.payment.PaymentAddr == nil &&
p.payment.BlindedPayment == nil { p.payment.BlindedPathSet == nil {
p.log.Debugf("not splitting because payment " + p.log.Debugf("not splitting because payment " +
"address is unspecified") "address is unspecified")
@ -407,11 +406,6 @@ func (p *paymentSession) RequestRoute(maxAmt, feeLimit lnwire.MilliSatoshi,
return nil, err return nil, err
} }
var blindedPath *sphinx.BlindedPath
if p.payment.BlindedPayment != nil {
blindedPath = p.payment.BlindedPayment.BlindedPath
}
// With the next candidate path found, we'll attempt to turn // With the next candidate path found, we'll attempt to turn
// this into a route by applying the time-lock and fee // this into a route by applying the time-lock and fee
// requirements. // requirements.
@ -424,7 +418,7 @@ func (p *paymentSession) RequestRoute(maxAmt, feeLimit lnwire.MilliSatoshi,
records: p.payment.DestCustomRecords, records: p.payment.DestCustomRecords,
paymentAddr: p.payment.PaymentAddr, paymentAddr: p.payment.PaymentAddr,
metadata: p.payment.Metadata, metadata: p.payment.Metadata,
}, blindedPath, }, p.payment.BlindedPathSet,
) )
if err != nil { if err != nil {
return nil, err return nil, err

View File

@ -477,10 +477,10 @@ type RouteRequest struct {
// in blinded payment. // in blinded payment.
FinalExpiry uint16 FinalExpiry uint16
// BlindedPayment contains an optional blinded path and parameters // BlindedPathSet contains a set of optional blinded paths and
// used to reach a target node via a blinded path. This field is // parameters used to reach a target node blinded paths. This field is
// mutually exclusive with the Target field. // mutually exclusive with the Target field.
BlindedPayment *BlindedPayment BlindedPathSet *BlindedPaymentPathSet
} }
// RouteHints is an alias type for a set of route hints, with the source node // RouteHints is an alias type for a set of route hints, with the source node
@ -494,7 +494,7 @@ type RouteHints map[route.Vertex][]AdditionalEdge
func NewRouteRequest(source route.Vertex, target *route.Vertex, func NewRouteRequest(source route.Vertex, target *route.Vertex,
amount lnwire.MilliSatoshi, timePref float64, amount lnwire.MilliSatoshi, timePref float64,
restrictions *RestrictParams, customRecords record.CustomSet, restrictions *RestrictParams, customRecords record.CustomSet,
routeHints RouteHints, blindedPayment *BlindedPayment, routeHints RouteHints, blindedPathSet *BlindedPaymentPathSet,
finalExpiry uint16) (*RouteRequest, error) { finalExpiry uint16) (*RouteRequest, error) {
var ( var (
@ -504,11 +504,8 @@ func NewRouteRequest(source route.Vertex, target *route.Vertex,
err error err error
) )
if blindedPayment != nil { if blindedPathSet != nil {
if err := blindedPayment.Validate(); err != nil { blindedPayment := blindedPathSet.GetPath()
return nil, fmt.Errorf("invalid blinded payment: %w",
err)
}
introVertex := route.NewVertex( introVertex := route.NewVertex(
blindedPayment.BlindedPath.IntroductionPoint, blindedPayment.BlindedPath.IntroductionPoint,
@ -539,13 +536,13 @@ func NewRouteRequest(source route.Vertex, target *route.Vertex,
requestExpiry = blindedPayment.CltvExpiryDelta requestExpiry = blindedPayment.CltvExpiryDelta
} }
requestHints, err = blindedPayment.toRouteHints() requestHints, err = blindedPathSet.ToRouteHints()
if err != nil { if err != nil {
return nil, err return nil, err
} }
} }
requestTarget, err := getTargetNode(target, blindedPayment) requestTarget, err := getTargetNode(target, blindedPathSet)
if err != nil { if err != nil {
return nil, err return nil, err
} }
@ -559,15 +556,15 @@ func NewRouteRequest(source route.Vertex, target *route.Vertex,
CustomRecords: customRecords, CustomRecords: customRecords,
RouteHints: requestHints, RouteHints: requestHints,
FinalExpiry: requestExpiry, FinalExpiry: requestExpiry,
BlindedPayment: blindedPayment, BlindedPathSet: blindedPathSet,
}, nil }, nil
} }
func getTargetNode(target *route.Vertex, blindedPayment *BlindedPayment) ( func getTargetNode(target *route.Vertex,
route.Vertex, error) { blindedPathSet *BlindedPaymentPathSet) (route.Vertex, error) {
var ( var (
blinded = blindedPayment != nil blinded = blindedPathSet != nil
targetSet = target != nil targetSet = target != nil
) )
@ -576,6 +573,8 @@ func getTargetNode(target *route.Vertex, blindedPayment *BlindedPayment) (
return route.Vertex{}, ErrTargetAndBlinded return route.Vertex{}, ErrTargetAndBlinded
case blinded: case blinded:
blindedPayment := blindedPathSet.GetPath()
// If we're dealing with an edge-case blinded path that just // If we're dealing with an edge-case blinded path that just
// has an introduction node (first hop expected to be the intro // has an introduction node (first hop expected to be the intro
// hop), then we return the unblinded introduction node as our // hop), then we return the unblinded introduction node as our
@ -597,16 +596,6 @@ func getTargetNode(target *route.Vertex, blindedPayment *BlindedPayment) (
} }
} }
// blindedPath returns the request's blinded path, which is set if the payment
// is to a blinded route.
func (r *RouteRequest) blindedPath() *sphinx.BlindedPath {
if r.BlindedPayment == nil {
return nil
}
return r.BlindedPayment.BlindedPath
}
// FindRoute attempts to query the ChannelRouter for the optimum path to a // FindRoute attempts to query the ChannelRouter for the optimum path to a
// particular target destination to which it is able to send `amt` after // particular target destination to which it is able to send `amt` after
// factoring in channel capacities and cumulative fees along the route. // factoring in channel capacities and cumulative fees along the route.
@ -664,7 +653,7 @@ func (r *ChannelRouter) FindRoute(req *RouteRequest) (*route.Route, float64,
totalAmt: req.Amount, totalAmt: req.Amount,
cltvDelta: req.FinalExpiry, cltvDelta: req.FinalExpiry,
records: req.CustomRecords, records: req.CustomRecords,
}, req.blindedPath(), }, req.BlindedPathSet,
) )
if err != nil { if err != nil {
return nil, 0, err return nil, 0, err
@ -926,14 +915,10 @@ type LightningPayment struct {
// BlindedPayment field. // BlindedPayment field.
RouteHints [][]zpay32.HopHint RouteHints [][]zpay32.HopHint
// BlindedPayment holds the information about a blinded path to the // BlindedPathSet holds the information about a set of blinded paths to
// payment recipient. This is mutually exclusive to the RouteHints // the payment recipient. This is mutually exclusive to the RouteHints
// field. // field.
// BlindedPathSet *BlindedPaymentPathSet
// NOTE: a recipient may provide multiple blinded payment paths in the
// same invoice. Currently, LND will only attempt to use the first one.
// A future PR will handle multiple blinded payment paths.
BlindedPayment *BlindedPayment
// OutgoingChannelIDs is the list of channels that are allowed for the // OutgoingChannelIDs is the list of channels that are allowed for the
// first hop. If nil, any channel may be used. // first hop. If nil, any channel may be used.

View File

@ -2223,11 +2223,6 @@ func TestNewRouteRequest(t *testing.T) {
finalExpiry: unblindedCltv, finalExpiry: unblindedCltv,
err: ErrExpiryAndBlinded, err: ErrExpiryAndBlinded,
}, },
{
name: "invalid blinded payment",
blindedPayment: &BlindedPayment{},
err: ErrNoBlindedPath,
},
} }
for _, testCase := range testCases { for _, testCase := range testCases {
@ -2236,9 +2231,19 @@ func TestNewRouteRequest(t *testing.T) {
t.Run(testCase.name, func(t *testing.T) { t.Run(testCase.name, func(t *testing.T) {
t.Parallel() t.Parallel()
var blindedPathInfo *BlindedPaymentPathSet
if testCase.blindedPayment != nil {
blindedPathInfo, err = NewBlindedPaymentPathSet(
[]*BlindedPayment{
testCase.blindedPayment,
},
)
require.NoError(t, err)
}
req, err := NewRouteRequest( req, err := NewRouteRequest(
source, testCase.target, 1000, 0, nil, nil, source, testCase.target, 1000, 0, nil, nil,
testCase.routeHints, testCase.blindedPayment, testCase.routeHints, blindedPathInfo,
testCase.finalExpiry, testCase.finalExpiry,
) )
require.ErrorIs(t, err, testCase.err) require.ErrorIs(t, err, testCase.err)

View File

@ -5105,7 +5105,7 @@ type rpcPaymentIntent struct {
paymentAddr *[32]byte paymentAddr *[32]byte
payReq []byte payReq []byte
metadata []byte metadata []byte
blindedPayment *routing.BlindedPayment blindedPathSet *routing.BlindedPaymentPathSet
destCustomRecords record.CustomSet destCustomRecords record.CustomSet
@ -5248,7 +5248,7 @@ func (r *rpcServer) extractPaymentIntent(rpcPayReq *rpcPaymentRequest) (rpcPayme
if err != nil { if err != nil {
return payIntent, err return payIntent, err
} }
payIntent.blindedPayment = pathSet.GetPath() payIntent.blindedPathSet = pathSet
// Replace the destination node with the target public // Replace the destination node with the target public
// key of the blinded path set. // key of the blinded path set.
@ -5417,7 +5417,7 @@ func (r *rpcServer) dispatchPaymentIntent(
DestFeatures: payIntent.destFeatures, DestFeatures: payIntent.destFeatures,
PaymentAddr: payIntent.paymentAddr, PaymentAddr: payIntent.paymentAddr,
Metadata: payIntent.metadata, Metadata: payIntent.metadata,
BlindedPayment: payIntent.blindedPayment, BlindedPathSet: payIntent.blindedPathSet,
// Don't enable multi-part payments on the main rpc. // Don't enable multi-part payments on the main rpc.
// Users need to use routerrpc for that. // Users need to use routerrpc for that.