@@ -30,8 +30,8 @@ import fr.acinq.eclair.payment.send.MultiPartPaymentLifecycle._
30
30
import fr .acinq .eclair .payment .send .PaymentError .RetryExhausted
31
31
import fr .acinq .eclair .payment .send .PaymentInitiator .SendPaymentConfig
32
32
import fr .acinq .eclair .payment .send .PaymentLifecycle .SendPaymentToRoute
33
- import fr .acinq .eclair .router .RouteNotFound
34
33
import fr .acinq .eclair .router .Router ._
34
+ import fr .acinq .eclair .router .{Announcements , RouteNotFound }
35
35
import fr .acinq .eclair .wire ._
36
36
import org .scalatest .Outcome
37
37
import org .scalatest .funsuite .FixtureAnyFunSuiteLike
@@ -261,6 +261,30 @@ class MultiPartPaymentLifecycleSpec extends TestKitBaseClass with FixtureAnyFunS
261
261
assert(router.expectMsgType[RouteRequest ].assistedRoutes.head.head === ExtraHop (b, channelUpdate.shortChannelId, 250 msat, 150 , CltvExpiryDelta (24 )))
262
262
}
263
263
264
+ test(" retry with ignored routing hints (temporary channel failure)" ) { f =>
265
+ import f ._
266
+
267
+ // The B -> E channel is private and provided in the invoice routing hints.
268
+ val routingHint = ExtraHop (b, hop_be.lastUpdate.shortChannelId, hop_be.lastUpdate.feeBaseMsat, hop_be.lastUpdate.feeProportionalMillionths, hop_be.lastUpdate.cltvExpiryDelta)
269
+ val payment = SendMultiPartPayment (sender.ref, randomBytes32, e, finalAmount, expiry, 3 , routeParams = Some (routeParams), assistedRoutes = List (List (routingHint)))
270
+ sender.send(payFsm, payment)
271
+ assert(router.expectMsgType[RouteRequest ].assistedRoutes.head.head === routingHint)
272
+ val route = Route (finalAmount, hop_ab_1 :: hop_be :: Nil )
273
+ router.send(payFsm, RouteResponse (Seq (route)))
274
+ childPayFsm.expectMsgType[SendPaymentToRoute ]
275
+ childPayFsm.expectNoMsg(100 millis)
276
+
277
+ // B doesn't have enough liquidity on this channel.
278
+ // NB: we need a channel update with a valid signature, otherwise we'll ignore the node instead of this specific channel.
279
+ val channelUpdate = Announcements .makeChannelUpdate(hop_be.lastUpdate.chainHash, priv_b, e, hop_be.lastUpdate.shortChannelId, hop_be.lastUpdate.cltvExpiryDelta, hop_be.lastUpdate.htlcMinimumMsat, hop_be.lastUpdate.feeBaseMsat, hop_be.lastUpdate.feeProportionalMillionths, hop_be.lastUpdate.htlcMaximumMsat.get)
280
+ val childId = payFsm.stateData.asInstanceOf [PaymentProgress ].pending.keys.head
281
+ childPayFsm.send(payFsm, PaymentFailed (childId, paymentHash, Seq (RemoteFailure (route.hops, Sphinx .DecryptedFailurePacket (b, TemporaryChannelFailure (channelUpdate))))))
282
+ // We update the routing hints accordingly before requesting a new route and ignore the channel.
283
+ val routeRequest = router.expectMsgType[RouteRequest ]
284
+ assert(routeRequest.assistedRoutes.head.head === routingHint)
285
+ assert(routeRequest.ignore.channels.map(_.shortChannelId) === Set (channelUpdate.shortChannelId))
286
+ }
287
+
264
288
test(" update routing hints" ) { _ =>
265
289
val routingHints = Seq (
266
290
Seq (ExtraHop (a, ShortChannelId (1 ), 10 msat, 0 , CltvExpiryDelta (12 )), ExtraHop (b, ShortChannelId (2 ), 0 msat, 100 , CltvExpiryDelta (24 ))),
@@ -536,7 +560,8 @@ object MultiPartPaymentLifecycleSpec {
536
560
* where a has multiple channels with each of his peers.
537
561
*/
538
562
539
- val a :: b :: c :: d :: e :: Nil = Seq .fill(5 )(randomKey.publicKey)
563
+ val priv_a :: priv_b :: priv_c :: priv_d :: priv_e :: Nil = Seq .fill(5 )(randomKey)
564
+ val a :: b :: c :: d :: e :: Nil = Seq (priv_a, priv_b, priv_c, priv_d, priv_e).map(_.publicKey)
540
565
val channelId_ab_1 = ShortChannelId (1 )
541
566
val channelId_ab_2 = ShortChannelId (2 )
542
567
val channelId_be = ShortChannelId (3 )
0 commit comments