@@ -100,8 +100,27 @@ func interpretResult(rt *mcRoute,
100
100
101
101
// processSuccess processes a successful payment attempt.
102
102
func (i * interpretedResult ) processSuccess (route * mcRoute ) {
103
- // For successes, all nodes must have acted in the right way. Therefore
104
- // we mark all of them with a success result.
103
+ // For successes, all nodes must have acted in the right way.
104
+ // Therefore we mark all of them with a success result. However we need
105
+ // to handle the blinded route part separately because for intermediate
106
+ // blinded nodes the amount field is set to zero so we use the receiver
107
+ // amount.
108
+ introIdx , isBlinded := introductionPointIndex (route )
109
+ if isBlinded {
110
+ // Report success for all the pairs until the introduction
111
+ // point.
112
+ i .successPairRange (route , 0 , introIdx - 1 )
113
+
114
+ // Handle the blinded route part.
115
+ //
116
+ // NOTE: The introIdx index here does describe the node after
117
+ // the introduction point.
118
+ i .markBlindedRouteSuccess (route , introIdx )
119
+
120
+ return
121
+ }
122
+
123
+ // Mark nodes as successful in the non-blinded case of the payment.
105
124
i .successPairRange (route , 0 , len (route .hops .Val )- 1 )
106
125
}
107
126
@@ -517,11 +536,22 @@ func (i *interpretedResult) processPaymentOutcomeIntermediate(route *mcRoute,
517
536
if introIdx == len (route .hops .Val )- 1 {
518
537
i .finalFailureReason = & reasonError
519
538
} else {
520
- // If there are other hops between the recipient and
521
- // introduction node, then we just penalize the last
522
- // hop in the blinded route to minimize the storage of
523
- // results for ephemeral keys.
524
- i .failPairBalance (route , len (route .hops .Val )- 1 )
539
+ // We penalize the final hop of the blinded route which
540
+ // is sufficient to not reuse this route again and is
541
+ // also more memory efficient because the other hops
542
+ // of the blinded path are ephemeral and will only be
543
+ // used in conjunction with the final hop. Moreover we
544
+ // don't want to punish the introduction node because
545
+ // the blinded failure does not necessarily mean that
546
+ // the introduction node was at fault.
547
+ //
548
+ // TODO(ziggie): Make sure we only keep mc data for
549
+ // blinded paths, in both the success and failure case,
550
+ // in memory during the time of the payment and remove
551
+ // it afterwards. Blinded paths and their blinded hop
552
+ // keys are always changing per blinded route so there
553
+ // is no point in persisting this data.
554
+ i .failBlindedRoute (route )
525
555
}
526
556
527
557
// In all other cases, we penalize the reporting node. These are all
@@ -828,6 +858,41 @@ func (i *interpretedResult) successPairRange(rt *mcRoute, fromIdx, toIdx int) {
828
858
}
829
859
}
830
860
861
+ // failBlindedRoute marks a blinded route as failed for the specific amount to
862
+ // send by only punishing the last pair.
863
+ func (i * interpretedResult ) failBlindedRoute (rt * mcRoute ) {
864
+ // We fail the last pair of the route, in order to fail the complete
865
+ // blinded route. This is because the combination of ephemeral pubkeys
866
+ // is unique to the route. We fail the last pair in order to not punish
867
+ // the introduction node, since we don't want to disincentivize them
868
+ // from providing that service.
869
+ pair , _ := getPair (rt , len (rt .hops .Val )- 1 )
870
+
871
+ // Since all the hops along a blinded path don't have any amount set, we
872
+ // extract the minimal amount to punish from the value that is tried to
873
+ // be sent to the receiver.
874
+ amt := rt .hops .Val [len (rt .hops .Val )- 1 ].amtToFwd .Val
875
+
876
+ i .pairResults [pair ] = failPairResult (amt )
877
+ }
878
+
879
+ // markBlindedRouteSuccess marks the hops of the blinded route AFTER the
880
+ // introduction node as successful.
881
+ //
882
+ // NOTE: The introIdx must be the index of the first hop of the blinded route
883
+ // AFTER the introduction node.
884
+ func (i * interpretedResult ) markBlindedRouteSuccess (rt * mcRoute , introIdx int ) {
885
+ // For blinded hops we do not have the forwarding amount so we take the
886
+ // minimal amount which went through the route by looking at the last
887
+ // hop.
888
+ successAmt := rt .hops .Val [len (rt .hops .Val )- 1 ].amtToFwd .Val
889
+ for idx := introIdx ; idx < len (rt .hops .Val ); idx ++ {
890
+ pair , _ := getPair (rt , idx )
891
+
892
+ i .pairResults [pair ] = successPairResult (successAmt )
893
+ }
894
+ }
895
+
831
896
// getPair returns a node pair from the route and the amount passed between that
832
897
// pair.
833
898
func getPair (rt * mcRoute , channelIdx int ) (DirectedNodePair ,
0 commit comments