1
0
Fork 0
mirror of https://github.com/ACINQ/eclair.git synced 2025-03-13 19:37:35 +01:00

Actively clean the routing table in payment lifecycle

On android there are some cases where we are not aware that a local public
channel as in fact been closed. If this happens we will tell the router to
forget about it.

If the channel is in fact still alive, we will get it again via network
announcements anyway.
This commit is contained in:
dpad85 2019-02-14 11:57:21 +01:00
parent 3ab935c468
commit 12412c5565
No known key found for this signature in database
GPG key ID: 574C8C6A1673E987
2 changed files with 21 additions and 9 deletions

View file

@ -69,6 +69,7 @@ class Register extends Actor with ActorLogging {
}
case fwd@ForwardShortId(shortChannelId, msg) =>
log.info("forwarding to shortChannelId={} with known shortIds={}", shortChannelId, shortIds)
shortIds.get(shortChannelId).flatMap(channels.get(_)) match {
case Some(channel) => channel forward msg
case None => sender ! Failure(ForwardShortIdFailure(fwd))

View file

@ -56,6 +56,7 @@ class PaymentLifecycle(sourceNodeId: PublicKey, router: ActorRef, register: Acto
val finalExpiry = Globals.blockCount.get().toInt + c.finalCltvExpiry.toInt + 1
val (cmd, sharedSecrets) = buildCommand(c.amountMsat, finalExpiry, c.paymentHash, hops)
log.info("forwarding shortId={} from firstHop.lastUpdate={}", firstHop.lastUpdate.shortChannelId, firstHop.lastUpdate)
register ! Register.ForwardShortId(firstHop.lastUpdate.shortChannelId, cmd)
goto(WAITING_FOR_PAYMENT_COMPLETE) using WaitingForComplete(s, c, cmd, failures, sharedSecrets, ignoreNodes, ignoreChannels, hops)
@ -160,16 +161,26 @@ class PaymentLifecycle(sourceNodeId: PublicKey, router: ActorRef, register: Acto
stay
case Event(Status.Failure(t), WaitingForComplete(s, c, _, failures, _, ignoreNodes, ignoreChannels, hops)) =>
if (failures.size + 1 >= c.maxAttempts) {
reply(s, PaymentFailed(c.paymentHash, failures :+ LocalFailure(t)))
stop(FSM.Normal)
} else {
log.info(s"received an error message from local, trying to use a different channel (failure=${t.getMessage})")
val faultyChannel = ChannelDesc(hops.head.lastUpdate.shortChannelId, hops.head.nodeId, hops.head.nextNodeId)
router ! RouteRequest(sourceNodeId, c.targetNodeId, c.amountMsat, c.assistedRoutes, ignoreNodes, ignoreChannels + faultyChannel, c.randomize, c.routeParams)
goto(WAITING_FOR_ROUTE) using WaitingForRoute(s, c, failures :+ LocalFailure(t))
t match {
case Register.ForwardShortIdFailure(fwd) =>
// On Android we don't actively clean the routing table so we may have cases where we are not aware that a local public channel as in fact been closed
// if this happens we will tell the router to forget about it
// note that if the channel is in fact still alive, we will get it again via network announcements anyway
log.warning(s"local shortChannelId=${fwd.shortChannelId} doesn't seem to exist, excluding it from routes")
router ! WatchEventSpentBasic(BITCOIN_FUNDING_EXTERNAL_CHANNEL_SPENT(fwd.shortChannelId))
router ! RouteRequest(sourceNodeId, c.targetNodeId, c.amountMsat, c.assistedRoutes, randomize = c.randomize, routeParams = c.routeParams)
goto(WAITING_FOR_ROUTE) using WaitingForRoute(s, c, failures)
case _ =>
if (failures.size + 1 >= c.maxAttempts) {
reply(s, PaymentFailed(c.paymentHash, failures :+ LocalFailure(t)))
stop(FSM.Normal)
} else {
log.info(s"received an error message from local, trying to use a different channel (failure=${t.getMessage})")
val faultyChannel = ChannelDesc(hops.head.lastUpdate.shortChannelId, hops.head.nodeId, hops.head.nextNodeId)
router ! RouteRequest(sourceNodeId, c.targetNodeId, c.amountMsat, c.assistedRoutes, ignoreNodes, ignoreChannels + faultyChannel, c.randomize, c.routeParams)
goto(WAITING_FOR_ROUTE) using WaitingForRoute(s, c, failures :+ LocalFailure(t))
}
}
}
whenUnhandled {