77 "github.com/btcsuite/btcd/btcec/v2"
88 sphinx "github.com/lightningnetwork/lightning-onion"
99 "github.com/lightningnetwork/lnd/channeldb/models"
10+ "github.com/lightningnetwork/lnd/fn"
1011 "github.com/lightningnetwork/lnd/lnwire"
1112 "github.com/lightningnetwork/lnd/routing/route"
1213)
@@ -86,16 +87,35 @@ func NewBlindedPaymentPathSet(paths []*BlindedPayment) (*BlindedPaymentPathSet,
8687 }
8788 }
8889
89- // NOTE: for now, we just take a single path. By the end of this PR
90- // series, all paths will be kept.
91- path := paths [0 ]
90+ // Derive an ephemeral target priv key that will be injected into each
91+ // blinded path final hop.
92+ targetPriv , err := btcec .NewPrivateKey ()
93+ if err != nil {
94+ return nil , err
95+ }
96+ targetPub := targetPriv .PubKey ()
97+
98+ // If any provided blinded path only has a single hop (ie, the
99+ // destination node is also the introduction node), then we discard all
100+ // other paths since we know the real pub key of the destination node.
101+ // For a single hop path, there is also no need for the pseudo target
102+ // pub key replacement, so our target pub key in this case just remains
103+ // the real introduction node ID.
104+ var pathSet = paths
105+ for _ , path := range paths {
106+ if len (path .BlindedPath .BlindedHops ) != 1 {
107+ continue
108+ }
92109
93- finalHop := path .BlindedPath .
94- BlindedHops [len (path .BlindedPath .BlindedHops )- 1 ]
110+ pathSet = []* BlindedPayment {path }
111+ targetPub = path .BlindedPath .IntroductionPoint
112+
113+ break
114+ }
95115
96116 return & BlindedPaymentPathSet {
97- paths : paths ,
98- targetPubKey : finalHop . BlindedNodePub ,
117+ paths : pathSet ,
118+ targetPubKey : targetPub ,
99119 features : features ,
100120 }, nil
101121}
@@ -144,7 +164,7 @@ func (s *BlindedPaymentPathSet) ToRouteHints() (RouteHints, error) {
144164 hints := make (RouteHints )
145165
146166 for _ , path := range s .paths {
147- pathHints , err := path .toRouteHints ()
167+ pathHints , err := path .toRouteHints (fn . Some ( s . targetPubKey ) )
148168 if err != nil {
149169 return nil , err
150170 }
@@ -223,8 +243,11 @@ func (b *BlindedPayment) Validate() error {
223243// effectively the final_cltv_delta for the receiving introduction node). In
224244// the case of multiple blinded hops, CLTV delta is fully accounted for in the
225245// hints (both for intermediate hops and the final_cltv_delta for the receiving
226- // node).
227- func (b * BlindedPayment ) toRouteHints () (RouteHints , error ) {
246+ // node). The pseudoTarget, if provided, will be used to override the pub key
247+ // of the destination node in the path.
248+ func (b * BlindedPayment ) toRouteHints (
249+ pseudoTarget fn.Option [* btcec.PublicKey ]) (RouteHints , error ) {
250+
228251 // If we just have a single hop in our blinded route, it just contains
229252 // an introduction node (this is a valid path according to the spec).
230253 // Since we have the un-blinded node ID for the introduction node, we
@@ -272,12 +295,12 @@ func (b *BlindedPayment) toRouteHints() (RouteHints, error) {
272295 ToNodeFeatures : features ,
273296 }
274297
275- edge , err := NewBlindedEdge (edgePolicy , b , 0 )
298+ lastEdge , err := NewBlindedEdge (edgePolicy , b , 0 )
276299 if err != nil {
277300 return nil , err
278301 }
279302
280- hints [fromNode ] = []AdditionalEdge {edge }
303+ hints [fromNode ] = []AdditionalEdge {lastEdge }
281304
282305 // Start at an offset of 1 because the first node in our blinded hops
283306 // is the introduction node and terminate at the second-last node
@@ -304,13 +327,24 @@ func (b *BlindedPayment) toRouteHints() (RouteHints, error) {
304327 ToNodeFeatures : features ,
305328 }
306329
307- edge , err : = NewBlindedEdge (edgePolicy , b , i )
330+ lastEdge , err = NewBlindedEdge (edgePolicy , b , i )
308331 if err != nil {
309332 return nil , err
310333 }
311334
312- hints [fromNode ] = []AdditionalEdge {edge }
335+ hints [fromNode ] = []AdditionalEdge {lastEdge }
313336 }
314337
338+ pseudoTarget .WhenSome (func (key * btcec.PublicKey ) {
339+ // For the very last hop on the path, switch out the ToNodePub
340+ // for the pseudo target pub key.
341+ lastEdge .policy .ToNodePubKey = func () route.Vertex {
342+ return route .NewVertex (key )
343+ }
344+
345+ // Then override the final hint with this updated edge.
346+ hints [fromNode ] = []AdditionalEdge {lastEdge }
347+ })
348+
315349 return hints , nil
316350}
0 commit comments