From f954ad7b272e036833b64f3f847ce689199e5cdd Mon Sep 17 00:00:00 2001 From: t-bast Date: Mon, 10 Jun 2024 17:16:55 +0200 Subject: [PATCH] Reorder functions in `NodeRelay.scala` This commit doesn't contain any logical change, we just move code to align with the FSM flow. It makes it easier to follow the progress of the state machine to always scroll down when advancing states. --- .../eclair/payment/relay/NodeRelay.scala | 140 +++++++++--------- 1 file changed, 69 insertions(+), 71 deletions(-) diff --git a/eclair-core/src/main/scala/fr/acinq/eclair/payment/relay/NodeRelay.scala b/eclair-core/src/main/scala/fr/acinq/eclair/payment/relay/NodeRelay.scala index 84d40c2ac3..1270917aa4 100644 --- a/eclair-core/src/main/scala/fr/acinq/eclair/payment/relay/NodeRelay.scala +++ b/eclair-core/src/main/scala/fr/acinq/eclair/payment/relay/NodeRelay.scala @@ -262,60 +262,6 @@ class NodeRelay private(nodeParams: NodeParams, relay(upstream, nextPayload, nextPacket_opt) } - /** - * Once the payment is forwarded, we're waiting for fail/fulfill responses from downstream nodes. - * - * @param upstream complete HTLC set received. - * @param nextPayload relay instructions. - * @param fulfilledUpstream true if we already fulfilled the payment upstream. - */ - private def sending(upstream: Upstream.Trampoline, nextPayload: IntermediatePayload.NodeRelay, startedAt: TimestampMilli, fulfilledUpstream: Boolean): Behavior[Command] = - Behaviors.receiveMessagePartial { - rejectExtraHtlcPartialFunction orElse { - // this is the fulfill that arrives from downstream channels - case WrappedPreimageReceived(PreimageReceived(_, paymentPreimage)) => - if (!fulfilledUpstream) { - // We want to fulfill upstream as soon as we receive the preimage (even if not all HTLCs have fulfilled downstream). - context.log.debug("got preimage from downstream") - fulfillPayment(upstream, paymentPreimage) - sending(upstream, nextPayload, startedAt, fulfilledUpstream = true) - } else { - // we don't want to fulfill multiple times - Behaviors.same - } - case WrappedPaymentSent(paymentSent) => - context.log.debug("trampoline payment fully resolved downstream") - success(upstream, fulfilledUpstream, paymentSent) - recordRelayDuration(startedAt, isSuccess = true) - stopping() - case WrappedPaymentFailed(PaymentFailed(_, _, failures, _)) => - context.log.debug(s"trampoline payment failed downstream") - if (!fulfilledUpstream) { - rejectPayment(upstream, translateError(nodeParams, failures, upstream, nextPayload)) - } - recordRelayDuration(startedAt, isSuccess = fulfilledUpstream) - stopping() - } - } - - /** - * Once the downstream payment is settled (fulfilled or failed), we reject new upstream payments while we wait for our parent to stop us. - */ - private def stopping(): Behavior[Command] = { - parent ! NodeRelayer.RelayComplete(context.self, paymentHash, paymentSecret) - Behaviors.receiveMessagePartial { - rejectExtraHtlcPartialFunction orElse { - case Stop => Behaviors.stopped - } - } - } - - private val payFsmAdapters = { - context.messageAdapter[PreimageReceived](WrappedPreimageReceived) - context.messageAdapter[PaymentSent](WrappedPaymentSent) - context.messageAdapter[PaymentFailed](WrappedPaymentFailed) - }.toClassic - private def relay(upstream: Upstream.Trampoline, payloadOut: IntermediatePayload.NodeRelay, packetOut_opt: Option[OnionRoutingPacket]): Behavior[Command] = { val displayNodeId = payloadOut match { case payloadOut: IntermediatePayload.NodeRelay.Standard => payloadOut.outgoingNodeId @@ -345,23 +291,6 @@ class NodeRelay private(nodeParams: NodeParams, } } - private def relayToRecipient(upstream: Upstream.Trampoline, - payloadOut: IntermediatePayload.NodeRelay, - recipient: Recipient, - paymentCfg: SendPaymentConfig, - routeParams: RouteParams, - useMultiPart: Boolean): Behavior[Command] = { - val payment = - if (useMultiPart) { - SendMultiPartPayment(payFsmAdapters, recipient, nodeParams.maxPaymentAttempts, routeParams) - } else { - SendPaymentToNode(payFsmAdapters, recipient, nodeParams.maxPaymentAttempts, routeParams) - } - val payFSM = outgoingPaymentFactory.spawnOutgoingPayFSM(context, paymentCfg, useMultiPart) - payFSM ! payment - sending(upstream, payloadOut, TimestampMilli.now(), fulfilledUpstream = false) - } - /** * Blinded paths in Bolt 12 invoices may encode the introduction node with an scid and a direction: we need to resolve * that to a nodeId in order to reach that introduction node and use the blinded path. @@ -384,6 +313,75 @@ class NodeRelay private(nodeParams: NodeParams, relayToRecipient(upstream, payloadOut, recipient, paymentCfg, routeParams, features.hasFeature(Features.BasicMultiPartPayment)) } + private def relayToRecipient(upstream: Upstream.Trampoline, + payloadOut: IntermediatePayload.NodeRelay, + recipient: Recipient, + paymentCfg: SendPaymentConfig, + routeParams: RouteParams, + useMultiPart: Boolean): Behavior[Command] = { + val payFsmAdapters = { + context.messageAdapter[PreimageReceived](WrappedPreimageReceived) + context.messageAdapter[PaymentSent](WrappedPaymentSent) + context.messageAdapter[PaymentFailed](WrappedPaymentFailed) + }.toClassic + val payment = if (useMultiPart) { + SendMultiPartPayment(payFsmAdapters, recipient, nodeParams.maxPaymentAttempts, routeParams) + } else { + SendPaymentToNode(payFsmAdapters, recipient, nodeParams.maxPaymentAttempts, routeParams) + } + val payFSM = outgoingPaymentFactory.spawnOutgoingPayFSM(context, paymentCfg, useMultiPart) + payFSM ! payment + sending(upstream, payloadOut, TimestampMilli.now(), fulfilledUpstream = false) + } + + /** + * Once the payment is forwarded, we're waiting for fail/fulfill responses from downstream nodes. + * + * @param upstream complete HTLC set received. + * @param nextPayload relay instructions. + * @param fulfilledUpstream true if we already fulfilled the payment upstream. + */ + private def sending(upstream: Upstream.Trampoline, nextPayload: IntermediatePayload.NodeRelay, startedAt: TimestampMilli, fulfilledUpstream: Boolean): Behavior[Command] = + Behaviors.receiveMessagePartial { + rejectExtraHtlcPartialFunction orElse { + // this is the fulfill that arrives from downstream channels + case WrappedPreimageReceived(PreimageReceived(_, paymentPreimage)) => + if (!fulfilledUpstream) { + // We want to fulfill upstream as soon as we receive the preimage (even if not all HTLCs have fulfilled downstream). + context.log.debug("got preimage from downstream") + fulfillPayment(upstream, paymentPreimage) + sending(upstream, nextPayload, startedAt, fulfilledUpstream = true) + } else { + // we don't want to fulfill multiple times + Behaviors.same + } + case WrappedPaymentSent(paymentSent) => + context.log.debug("trampoline payment fully resolved downstream") + success(upstream, fulfilledUpstream, paymentSent) + recordRelayDuration(startedAt, isSuccess = true) + stopping() + case WrappedPaymentFailed(PaymentFailed(_, _, failures, _)) => + context.log.debug(s"trampoline payment failed downstream") + if (!fulfilledUpstream) { + rejectPayment(upstream, translateError(nodeParams, failures, upstream, nextPayload)) + } + recordRelayDuration(startedAt, isSuccess = fulfilledUpstream) + stopping() + } + } + + /** + * Once the downstream payment is settled (fulfilled or failed), we reject new upstream payments while we wait for our parent to stop us. + */ + private def stopping(): Behavior[Command] = { + parent ! NodeRelayer.RelayComplete(context.self, paymentHash, paymentSecret) + Behaviors.receiveMessagePartial { + rejectExtraHtlcPartialFunction orElse { + case Stop => Behaviors.stopped + } + } + } + private def rejectExtraHtlcPartialFunction: PartialFunction[Command, Behavior[Command]] = { case Relay(nodeRelayPacket) => rejectExtraHtlc(nodeRelayPacket.add)