Skip to content

Commit

Permalink
Emit sensitive task event for MPP (#585)
Browse files Browse the repository at this point in the history
When the first part of a multi-part payment is received, we emit a
`SensitiveTaskEvents.TaskStarted` hoping that iOS will let the app
running long enough for subsequent parts to arrive.
  • Loading branch information
pm47 authored Jan 23, 2024
1 parent e3c90bf commit 507e3b1
Show file tree
Hide file tree
Showing 3 changed files with 15 additions and 4 deletions.
1 change: 1 addition & 0 deletions src/commonMain/kotlin/fr/acinq/lightning/NodeEvents.kt
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ sealed interface SensitiveTaskEvents : NodeEvents {
data class InteractiveTx(val channelId: ByteVector32, val fundingTxIndex: Long) : TaskIdentifier() {
constructor(fundingParams: InteractiveTxParams) : this(fundingParams.channelId, (fundingParams.sharedInput as? SharedFundingInput.Multisig2of2)?.fundingTxIndex?.let { it + 1 } ?: 0)
}
data class IncomingMultiPartPayment(val paymentHash: ByteVector32) : TaskIdentifier()
}
data class TaskStarted(val id: TaskIdentifier) : SensitiveTaskEvents
data class TaskEnded(val id: TaskIdentifier) : SensitiveTaskEvents
Expand Down
12 changes: 11 additions & 1 deletion src/commonMain/kotlin/fr/acinq/lightning/io/Peer.kt
Original file line number Diff line number Diff line change
Expand Up @@ -795,7 +795,17 @@ class Peer(
is Either.Left -> incomingPaymentHandler.process(item.value, currentBlockHeight)
}
when (result) {
is IncomingPaymentHandler.ProcessAddResult.Accepted -> _eventsFlow.emit(PaymentReceived(result.incomingPayment, result.received))
is IncomingPaymentHandler.ProcessAddResult.Accepted -> {
if ((result.incomingPayment.received?.receivedWith?.size ?: 0) > 1) {
// this was a multi-part payment, we signal that the task is finished
nodeParams._nodeEvents.tryEmit(SensitiveTaskEvents.TaskEnded(SensitiveTaskEvents.TaskIdentifier.IncomingMultiPartPayment(result.incomingPayment.paymentHash)))
}
_eventsFlow.emit(PaymentReceived(result.incomingPayment, result.received))
}
is IncomingPaymentHandler.ProcessAddResult.Pending -> if (result.pendingPayment.parts.size == 1) {
// this is the first part of a multi-part payment, we request to keep the app alive to receive subsequent parts
nodeParams._nodeEvents.tryEmit(SensitiveTaskEvents.TaskStarted(SensitiveTaskEvents.TaskIdentifier.IncomingMultiPartPayment(result.incomingPayment.paymentHash)))
}
else -> Unit
}
result.actions.forEach { input.send(it) }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ class IncomingPaymentHandler(val nodeParams: NodeParams, val db: IncomingPayment

data class Accepted(override val actions: List<PeerCommand>, val incomingPayment: IncomingPayment, val received: IncomingPayment.Received) : ProcessAddResult()
data class Rejected(override val actions: List<PeerCommand>, val incomingPayment: IncomingPayment?) : ProcessAddResult()
data class Pending(val incomingPayment: IncomingPayment) : ProcessAddResult() {
data class Pending(val incomingPayment: IncomingPayment, val pendingPayment: PendingPayment) : ProcessAddResult() {
override val actions: List<PeerCommand> = listOf()
}
}
Expand All @@ -63,7 +63,7 @@ class IncomingPaymentHandler(val nodeParams: NodeParams, val db: IncomingPayment
* @param totalAmount total amount that should be received.
* @param startedAtSeconds time at which we received the first partial payment (in seconds).
*/
private data class PendingPayment(val parts: Set<PaymentPart>, val totalAmount: MilliSatoshi, val startedAtSeconds: Long) {
data class PendingPayment(val parts: Set<PaymentPart>, val totalAmount: MilliSatoshi, val startedAtSeconds: Long) {
constructor(firstPart: PaymentPart) : this(setOf(firstPart), firstPart.totalAmount, currentTimestampSeconds())

val amountReceived: MilliSatoshi = parts.map { it.amount }.sum()
Expand Down Expand Up @@ -246,7 +246,7 @@ class IncomingPaymentHandler(val nodeParams: NodeParams, val db: IncomingPayment
payment.amountReceived < payment.totalAmount -> {
// Still waiting for more payments.
pending[paymentPart.paymentHash] = payment
return ProcessAddResult.Pending(incomingPayment)
return ProcessAddResult.Pending(incomingPayment, payment)
}
else -> {
if (payment.parts.filterIsInstance<PayToOpenPart>().isNotEmpty()) {
Expand Down

0 comments on commit 507e3b1

Please sign in to comment.