mirror of
https://github.com/ACINQ/eclair.git
synced 2025-03-13 19:37:35 +01:00
Add DB entry for payment router error (#1513)
When using MPP, if we can't find a route, we need to add an entry to the DB. Otherwise when users query their payment status, nothing will be returned which is a bad UX. Fixes #1512
This commit is contained in:
parent
ebed70b93c
commit
9bb992bbc9
4 changed files with 22 additions and 0 deletions
|
@ -200,6 +200,7 @@ object HopSummary {
|
|||
case class FailureSummary(failureType: FailureType.Value, failureMessage: String, failedRoute: List[HopSummary])
|
||||
|
||||
object FailureType extends Enumeration {
|
||||
type FailureType = Value
|
||||
val LOCAL = Value(1, "Local")
|
||||
val REMOTE = Value(2, "Remote")
|
||||
val UNREADABLE_REMOTE = Value(3, "UnreadableRemote")
|
||||
|
|
|
@ -24,6 +24,7 @@ import akka.event.Logging.MDC
|
|||
import fr.acinq.bitcoin.ByteVector32
|
||||
import fr.acinq.bitcoin.Crypto.PublicKey
|
||||
import fr.acinq.eclair.channel.Upstream
|
||||
import fr.acinq.eclair.db.{OutgoingPayment, OutgoingPaymentStatus, PaymentType}
|
||||
import fr.acinq.eclair.payment.Monitoring.{Metrics, Tags}
|
||||
import fr.acinq.eclair.payment.PaymentRequest.ExtraHop
|
||||
import fr.acinq.eclair.payment.PaymentSent.PartialPayment
|
||||
|
@ -113,6 +114,13 @@ class MultiPartPaymentLifecycle(nodeParams: NodeParams, cfg: SendPaymentConfig,
|
|||
} else {
|
||||
val failure = LocalFailure(Nil, t)
|
||||
Metrics.PaymentError.withTag(Tags.Failure, Tags.FailureType(failure)).increment()
|
||||
if (cfg.storeInDb && d.pending.isEmpty && d.failures.isEmpty) {
|
||||
// In cases where we fail early (router error during the first attempt), the DB won't have an entry for that
|
||||
// payment, which may be confusing for users.
|
||||
val dummyPayment = OutgoingPayment(id, cfg.parentId, cfg.externalId, paymentHash, PaymentType.Standard, cfg.recipientAmount, cfg.recipientAmount, cfg.recipientNodeId, System.currentTimeMillis, cfg.paymentRequest, OutgoingPaymentStatus.Pending)
|
||||
nodeParams.db.payments.addOutgoingPayment(dummyPayment)
|
||||
nodeParams.db.payments.updateOutgoingPayment(PaymentFailed(id, paymentHash, failure :: Nil))
|
||||
}
|
||||
gotoAbortedOrStop(PaymentAborted(d.sender, d.request, d.failures :+ failure, d.pending.keySet))
|
||||
}
|
||||
|
||||
|
|
|
@ -24,6 +24,7 @@ import fr.acinq.bitcoin.{Block, Crypto}
|
|||
import fr.acinq.eclair._
|
||||
import fr.acinq.eclair.channel.{AddHtlcFailed, ChannelFlags, ChannelUnavailable, Upstream}
|
||||
import fr.acinq.eclair.crypto.Sphinx
|
||||
import fr.acinq.eclair.db.{FailureSummary, FailureType, OutgoingPaymentStatus}
|
||||
import fr.acinq.eclair.payment.send.MultiPartPaymentLifecycle
|
||||
import fr.acinq.eclair.payment.send.MultiPartPaymentLifecycle._
|
||||
import fr.acinq.eclair.payment.send.PaymentError.RetryExhausted
|
||||
|
@ -275,6 +276,10 @@ class MultiPartPaymentLifecycleSpec extends TestKitBaseClass with FixtureAnyFunS
|
|||
assert(result.paymentHash === paymentHash)
|
||||
assert(result.failures === Seq(LocalFailure(Nil, RouteNotFound)))
|
||||
|
||||
val Some(outgoing) = nodeParams.db.payments.getOutgoingPayment(cfg.id)
|
||||
assert(outgoing.status.isInstanceOf[OutgoingPaymentStatus.Failed])
|
||||
assert(outgoing.status.asInstanceOf[OutgoingPaymentStatus.Failed].failures === Seq(FailureSummary(FailureType.LOCAL, RouteNotFound.getMessage, Nil)))
|
||||
|
||||
sender.expectTerminated(payFsm)
|
||||
sender.expectNoMsg(100 millis)
|
||||
router.expectNoMsg(100 millis)
|
||||
|
|
|
@ -25,6 +25,7 @@ import fr.acinq.bitcoin.{ByteVector32, ByteVector64, OutPoint, Satoshi, Transact
|
|||
import fr.acinq.eclair.ApiTypes.ChannelIdentifier
|
||||
import fr.acinq.eclair.channel.{ChannelCommandResponse, ChannelVersion, State}
|
||||
import fr.acinq.eclair.crypto.ShaChain
|
||||
import fr.acinq.eclair.db.FailureType.FailureType
|
||||
import fr.acinq.eclair.db.{IncomingPaymentStatus, OutgoingPaymentStatus}
|
||||
import fr.acinq.eclair.payment._
|
||||
import fr.acinq.eclair.router.Router.RouteResponse
|
||||
|
@ -210,6 +211,12 @@ class FailureMessageSerializer extends CustomSerializer[FailureMessage](_ => ( {
|
|||
case m: FailureMessage => JString(m.message)
|
||||
}))
|
||||
|
||||
class FailureTypeSerializer extends CustomSerializer[FailureType](_ => ( {
|
||||
null
|
||||
}, {
|
||||
case ft: FailureType => JString(ft.toString)
|
||||
}))
|
||||
|
||||
class NodeAddressSerializer extends CustomSerializer[NodeAddress](_ => ( {
|
||||
null
|
||||
}, {
|
||||
|
@ -295,6 +302,7 @@ object JsonSupport extends Json4sJacksonSupport {
|
|||
new RouteResponseSerializer +
|
||||
new ThrowableSerializer +
|
||||
new FailureMessageSerializer +
|
||||
new FailureTypeSerializer +
|
||||
new NodeAddressSerializer +
|
||||
new DirectedHtlcSerializer +
|
||||
new PaymentRequestSerializer +
|
||||
|
|
Loading…
Add table
Reference in a new issue