@@ -51,6 +51,22 @@ type BlindedPaymentPathSet struct {
5151 // moment we require that all paths for the same payment have the
5252 // same feature set.
5353 features * lnwire.FeatureVector
54+
55+ // finalCLTV is the final hop's expiry delta of _any_ path in the set.
56+ // For any multi-hop path, the final CLTV delta should be seen as zero
57+ // since the final hop's final CLTV delta is accounted for in the
58+ // accumulated path policy values. The only edge case is for when the
59+ // final hop in the path is also the introduction node in which case
60+ // that path's FinalCLTV must be the non-zero min CLTV of the final hop
61+ // so that it is accounted for in path finding. For this reason, if
62+ // we have any single path in the set with only one hop, then we throw
63+ // away all the other paths. This should be fine to do since if there is
64+ // a path where the intro node is also the destination node, then there
65+ // isn't any need to try any other longer blinded path. In other words,
66+ // if this value is non-zero, then there is only one path in this
67+ // blinded path set and that path only has a single hop: the
68+ // introduction node.
69+ finalCLTV uint16
5470}
5571
5672// NewBlindedPaymentPathSet constructs a new BlindedPaymentPathSet from a set of
@@ -95,19 +111,25 @@ func NewBlindedPaymentPathSet(paths []*BlindedPayment) (*BlindedPaymentPathSet,
95111 }
96112 targetPub := targetPriv .PubKey ()
97113
114+ var (
115+ pathSet = paths
116+ finalCLTVDelta uint16
117+ )
98118 // If any provided blinded path only has a single hop (ie, the
99119 // destination node is also the introduction node), then we discard all
100120 // 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
121+ // We also then set the final CLTV delta to the path's delta since
122+ // there are no other edge hints that will account for it. For a single
123+ // hop path, there is also no need for the pseudo target pub key
124+ // replacement, so our target pub key in this case just remains the
125+ // real introduction node ID.
105126 for _ , path := range paths {
106127 if len (path .BlindedPath .BlindedHops ) != 1 {
107128 continue
108129 }
109130
110131 pathSet = []* BlindedPayment {path }
132+ finalCLTVDelta = path .CltvExpiryDelta
111133 targetPub = path .BlindedPath .IntroductionPoint
112134
113135 break
@@ -117,6 +139,7 @@ func NewBlindedPaymentPathSet(paths []*BlindedPayment) (*BlindedPaymentPathSet,
117139 paths : pathSet ,
118140 targetPubKey : targetPub ,
119141 features : features ,
142+ finalCLTV : finalCLTVDelta ,
120143 }, nil
121144}
122145
@@ -137,6 +160,15 @@ func (s *BlindedPaymentPathSet) GetPath() *BlindedPayment {
137160 return s .paths [0 ]
138161}
139162
163+ // FinalCLTVDelta is the minimum CLTV delta to use for the final hop on the
164+ // route. In most cases this will return zero since the value is accounted for
165+ // in the path's accumulated CLTVExpiryDelta. Only in the edge case of the path
166+ // set only including a single path which only includes an introduction node
167+ // will this return a non-zero value.
168+ func (s * BlindedPaymentPathSet ) FinalCLTVDelta () uint16 {
169+ return s .finalCLTV
170+ }
171+
140172// LargestLastHopPayloadPath returns the BlindedPayment in the set that has the
141173// largest last-hop payload. This is to be used for onion size estimation in
142174// path finding.
0 commit comments