@@ -1104,185 +1104,7 @@ func (s *Switch) handlePacketForward(packet *htlcPacket) error {
11041104 // payment circuit within our internal state so we can properly forward
11051105 // the ultimate settle message back latter.
11061106 case * lnwire.UpdateAddHTLC :
1107- // Check if the node is set to reject all onward HTLCs and also make
1108- // sure that HTLC is not from the source node.
1109- if s .cfg .RejectHTLC {
1110- failure := NewDetailedLinkError (
1111- & lnwire.FailChannelDisabled {},
1112- OutgoingFailureForwardsDisabled ,
1113- )
1114-
1115- return s .failAddPacket (packet , failure )
1116- }
1117-
1118- // Before we attempt to find a non-strict forwarding path for
1119- // this htlc, check whether the htlc is being routed over the
1120- // same incoming and outgoing channel. If our node does not
1121- // allow forwards of this nature, we fail the htlc early. This
1122- // check is in place to disallow inefficiently routed htlcs from
1123- // locking up our balance. With channels where the
1124- // option-scid-alias feature was negotiated, we also have to be
1125- // sure that the IDs aren't the same since one or both could be
1126- // an alias.
1127- linkErr := s .checkCircularForward (
1128- packet .incomingChanID , packet .outgoingChanID ,
1129- s .cfg .AllowCircularRoute , htlc .PaymentHash ,
1130- )
1131- if linkErr != nil {
1132- return s .failAddPacket (packet , linkErr )
1133- }
1134-
1135- s .indexMtx .RLock ()
1136- targetLink , err := s .getLinkByMapping (packet )
1137- if err != nil {
1138- s .indexMtx .RUnlock ()
1139-
1140- log .Debugf ("unable to find link with " +
1141- "destination %v" , packet .outgoingChanID )
1142-
1143- // If packet was forwarded from another channel link
1144- // than we should notify this link that some error
1145- // occurred.
1146- linkError := NewLinkError (
1147- & lnwire.FailUnknownNextPeer {},
1148- )
1149-
1150- return s .failAddPacket (packet , linkError )
1151- }
1152- targetPeerKey := targetLink .PeerPubKey ()
1153- interfaceLinks , _ := s .getLinks (targetPeerKey )
1154- s .indexMtx .RUnlock ()
1155-
1156- // We'll keep track of any HTLC failures during the link
1157- // selection process. This way we can return the error for
1158- // precise link that the sender selected, while optimistically
1159- // trying all links to utilize our available bandwidth.
1160- linkErrs := make (map [lnwire.ShortChannelID ]* LinkError )
1161-
1162- // Find all destination channel links with appropriate
1163- // bandwidth.
1164- var destinations []ChannelLink
1165- for _ , link := range interfaceLinks {
1166- var failure * LinkError
1167-
1168- // We'll skip any links that aren't yet eligible for
1169- // forwarding.
1170- if ! link .EligibleToForward () {
1171- failure = NewDetailedLinkError (
1172- & lnwire.FailUnknownNextPeer {},
1173- OutgoingFailureLinkNotEligible ,
1174- )
1175- } else {
1176- // We'll ensure that the HTLC satisfies the
1177- // current forwarding conditions of this target
1178- // link.
1179- currentHeight := atomic .LoadUint32 (& s .bestHeight )
1180- failure = link .CheckHtlcForward (
1181- htlc .PaymentHash , packet .incomingAmount ,
1182- packet .amount , packet .incomingTimeout ,
1183- packet .outgoingTimeout ,
1184- packet .inboundFee ,
1185- currentHeight ,
1186- packet .originalOutgoingChanID ,
1187- )
1188- }
1189-
1190- // If this link can forward the htlc, add it to the set
1191- // of destinations.
1192- if failure == nil {
1193- destinations = append (destinations , link )
1194- continue
1195- }
1196-
1197- linkErrs [link .ShortChanID ()] = failure
1198- }
1199-
1200- // If we had a forwarding failure due to the HTLC not
1201- // satisfying the current policy, then we'll send back an
1202- // error, but ensure we send back the error sourced at the
1203- // *target* link.
1204- if len (destinations ) == 0 {
1205- // At this point, some or all of the links rejected the
1206- // HTLC so we couldn't forward it. So we'll try to look
1207- // up the error that came from the source.
1208- linkErr , ok := linkErrs [packet .outgoingChanID ]
1209- if ! ok {
1210- // If we can't find the error of the source,
1211- // then we'll return an unknown next peer,
1212- // though this should never happen.
1213- linkErr = NewLinkError (
1214- & lnwire.FailUnknownNextPeer {},
1215- )
1216- log .Warnf ("unable to find err source for " +
1217- "outgoing_link=%v, errors=%v" ,
1218- packet .outgoingChanID ,
1219- lnutils .SpewLogClosure (linkErrs ))
1220- }
1221-
1222- log .Tracef ("incoming HTLC(%x) violated " +
1223- "target outgoing link (id=%v) policy: %v" ,
1224- htlc .PaymentHash [:], packet .outgoingChanID ,
1225- linkErr )
1226-
1227- return s .failAddPacket (packet , linkErr )
1228- }
1229-
1230- // Choose a random link out of the set of links that can forward
1231- // this htlc. The reason for randomization is to evenly
1232- // distribute the htlc load without making assumptions about
1233- // what the best channel is.
1234- destination := destinations [rand .Intn (len (destinations ))] // nolint:gosec
1235-
1236- // Retrieve the incoming link by its ShortChannelID. Note that
1237- // the incomingChanID is never set to hop.Source here.
1238- s .indexMtx .RLock ()
1239- incomingLink , err := s .getLinkByShortID (packet .incomingChanID )
1240- s .indexMtx .RUnlock ()
1241- if err != nil {
1242- // If we couldn't find the incoming link, we can't
1243- // evaluate the incoming's exposure to dust, so we just
1244- // fail the HTLC back.
1245- linkErr := NewLinkError (
1246- & lnwire.FailTemporaryChannelFailure {},
1247- )
1248-
1249- return s .failAddPacket (packet , linkErr )
1250- }
1251-
1252- // Evaluate whether this HTLC would increase our fee exposure
1253- // over the threshold on the incoming link. If it does, fail it
1254- // backwards.
1255- if s .dustExceedsFeeThreshold (
1256- incomingLink , packet .incomingAmount , true ,
1257- ) {
1258- // The incoming dust exceeds the threshold, so we fail
1259- // the add back.
1260- linkErr := NewLinkError (
1261- & lnwire.FailTemporaryChannelFailure {},
1262- )
1263-
1264- return s .failAddPacket (packet , linkErr )
1265- }
1266-
1267- // Also evaluate whether this HTLC would increase our fee
1268- // exposure over the threshold on the destination link. If it
1269- // does, fail it back.
1270- if s .dustExceedsFeeThreshold (
1271- destination , packet .amount , false ,
1272- ) {
1273- // The outgoing dust exceeds the threshold, so we fail
1274- // the add back.
1275- linkErr := NewLinkError (
1276- & lnwire.FailTemporaryChannelFailure {},
1277- )
1278-
1279- return s .failAddPacket (packet , linkErr )
1280- }
1281-
1282- // Send the packet to the destination channel link which
1283- // manages the channel.
1284- packet .outgoingChanID = destination .ShortChanID ()
1285- return destination .handleSwitchPacket (packet )
1107+ return s .handlePacketAdd (packet , htlc )
12861108
12871109 case * lnwire.UpdateFailHTLC , * lnwire.UpdateFulfillHTLC :
12881110 // If the source of this packet has not been set, use the
@@ -3052,3 +2874,180 @@ func (s *Switch) AddAliasForLink(chanID lnwire.ChannelID,
30522874
30532875 return nil
30542876}
2877+
2878+ // handlePacketAdd handles forwarding an Add packet.
2879+ func (s * Switch ) handlePacketAdd (packet * htlcPacket ,
2880+ htlc * lnwire.UpdateAddHTLC ) error {
2881+
2882+ // Check if the node is set to reject all onward HTLCs and also make
2883+ // sure that HTLC is not from the source node.
2884+ if s .cfg .RejectHTLC {
2885+ failure := NewDetailedLinkError (
2886+ & lnwire.FailChannelDisabled {},
2887+ OutgoingFailureForwardsDisabled ,
2888+ )
2889+
2890+ return s .failAddPacket (packet , failure )
2891+ }
2892+
2893+ // Before we attempt to find a non-strict forwarding path for this
2894+ // htlc, check whether the htlc is being routed over the same incoming
2895+ // and outgoing channel. If our node does not allow forwards of this
2896+ // nature, we fail the htlc early. This check is in place to disallow
2897+ // inefficiently routed htlcs from locking up our balance. With
2898+ // channels where the option-scid-alias feature was negotiated, we also
2899+ // have to be sure that the IDs aren't the same since one or both could
2900+ // be an alias.
2901+ linkErr := s .checkCircularForward (
2902+ packet .incomingChanID , packet .outgoingChanID ,
2903+ s .cfg .AllowCircularRoute , htlc .PaymentHash ,
2904+ )
2905+ if linkErr != nil {
2906+ return s .failAddPacket (packet , linkErr )
2907+ }
2908+
2909+ s .indexMtx .RLock ()
2910+ targetLink , err := s .getLinkByMapping (packet )
2911+ if err != nil {
2912+ s .indexMtx .RUnlock ()
2913+
2914+ log .Debugf ("unable to find link with " +
2915+ "destination %v" , packet .outgoingChanID )
2916+
2917+ // If packet was forwarded from another channel link than we
2918+ // should notify this link that some error occurred.
2919+ linkError := NewLinkError (
2920+ & lnwire.FailUnknownNextPeer {},
2921+ )
2922+
2923+ return s .failAddPacket (packet , linkError )
2924+ }
2925+ targetPeerKey := targetLink .PeerPubKey ()
2926+ interfaceLinks , _ := s .getLinks (targetPeerKey )
2927+ s .indexMtx .RUnlock ()
2928+
2929+ // We'll keep track of any HTLC failures during the link selection
2930+ // process. This way we can return the error for precise link that the
2931+ // sender selected, while optimistically trying all links to utilize
2932+ // our available bandwidth.
2933+ linkErrs := make (map [lnwire.ShortChannelID ]* LinkError )
2934+
2935+ // Find all destination channel links with appropriate bandwidth.
2936+ var destinations []ChannelLink
2937+ for _ , link := range interfaceLinks {
2938+ var failure * LinkError
2939+
2940+ // We'll skip any links that aren't yet eligible for
2941+ // forwarding.
2942+ if ! link .EligibleToForward () {
2943+ failure = NewDetailedLinkError (
2944+ & lnwire.FailUnknownNextPeer {},
2945+ OutgoingFailureLinkNotEligible ,
2946+ )
2947+ } else {
2948+ // We'll ensure that the HTLC satisfies the current
2949+ // forwarding conditions of this target link.
2950+ currentHeight := atomic .LoadUint32 (& s .bestHeight )
2951+ failure = link .CheckHtlcForward (
2952+ htlc .PaymentHash , packet .incomingAmount ,
2953+ packet .amount , packet .incomingTimeout ,
2954+ packet .outgoingTimeout ,
2955+ packet .inboundFee ,
2956+ currentHeight ,
2957+ packet .originalOutgoingChanID ,
2958+ )
2959+ }
2960+
2961+ // If this link can forward the htlc, add it to the set of
2962+ // destinations.
2963+ if failure == nil {
2964+ destinations = append (destinations , link )
2965+ continue
2966+ }
2967+
2968+ linkErrs [link .ShortChanID ()] = failure
2969+ }
2970+
2971+ // If we had a forwarding failure due to the HTLC not satisfying the
2972+ // current policy, then we'll send back an error, but ensure we send
2973+ // back the error sourced at the *target* link.
2974+ if len (destinations ) == 0 {
2975+ // At this point, some or all of the links rejected the HTLC so
2976+ // we couldn't forward it. So we'll try to look up the error
2977+ // that came from the source.
2978+ linkErr , ok := linkErrs [packet .outgoingChanID ]
2979+ if ! ok {
2980+ // If we can't find the error of the source, then we'll
2981+ // return an unknown next peer, though this should
2982+ // never happen.
2983+ linkErr = NewLinkError (
2984+ & lnwire.FailUnknownNextPeer {},
2985+ )
2986+ log .Warnf ("unable to find err source for " +
2987+ "outgoing_link=%v, errors=%v" ,
2988+ packet .outgoingChanID ,
2989+ lnutils .SpewLogClosure (linkErrs ))
2990+ }
2991+
2992+ log .Tracef ("incoming HTLC(%x) violated " +
2993+ "target outgoing link (id=%v) policy: %v" ,
2994+ htlc .PaymentHash [:], packet .outgoingChanID ,
2995+ linkErr )
2996+
2997+ return s .failAddPacket (packet , linkErr )
2998+ }
2999+
3000+ // Choose a random link out of the set of links that can forward this
3001+ // htlc. The reason for randomization is to evenly distribute the htlc
3002+ // load without making assumptions about what the best channel is.
3003+ destination := destinations [rand .Intn (len (destinations ))] // nolint:gosec
3004+
3005+ // Retrieve the incoming link by its ShortChannelID. Note that the
3006+ // incomingChanID is never set to hop.Source here.
3007+ s .indexMtx .RLock ()
3008+ incomingLink , err := s .getLinkByShortID (packet .incomingChanID )
3009+ s .indexMtx .RUnlock ()
3010+ if err != nil {
3011+ // If we couldn't find the incoming link, we can't evaluate the
3012+ // incoming's exposure to dust, so we just fail the HTLC back.
3013+ linkErr := NewLinkError (
3014+ & lnwire.FailTemporaryChannelFailure {},
3015+ )
3016+
3017+ return s .failAddPacket (packet , linkErr )
3018+ }
3019+
3020+ // Evaluate whether this HTLC would increase our fee exposure over the
3021+ // threshold on the incoming link. If it does, fail it backwards.
3022+ if s .dustExceedsFeeThreshold (
3023+ incomingLink , packet .incomingAmount , true ,
3024+ ) {
3025+ // The incoming dust exceeds the threshold, so we fail the add
3026+ // back.
3027+ linkErr := NewLinkError (
3028+ & lnwire.FailTemporaryChannelFailure {},
3029+ )
3030+
3031+ return s .failAddPacket (packet , linkErr )
3032+ }
3033+
3034+ // Also evaluate whether this HTLC would increase our fee exposure over
3035+ // the threshold on the destination link. If it does, fail it back.
3036+ if s .dustExceedsFeeThreshold (
3037+ destination , packet .amount , false ,
3038+ ) {
3039+ // The outgoing dust exceeds the threshold, so we fail the add
3040+ // back.
3041+ linkErr := NewLinkError (
3042+ & lnwire.FailTemporaryChannelFailure {},
3043+ )
3044+
3045+ return s .failAddPacket (packet , linkErr )
3046+ }
3047+
3048+ // Send the packet to the destination channel link which manages the
3049+ // channel.
3050+ packet .outgoingChanID = destination .ShortChanID ()
3051+
3052+ return destination .handleSwitchPacket (packet )
3053+ }
0 commit comments