Skip to content

Commit 1d6a225

Browse files
committed
receivedAt in IncomingPaymentPacket
1 parent 3230761 commit 1d6a225

File tree

15 files changed

+138
-128
lines changed

15 files changed

+138
-128
lines changed

eclair-core/src/main/scala/fr/acinq/eclair/payment/PaymentEvents.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -85,26 +85,26 @@ case class PaymentFailed(id: UUID, paymentHash: ByteVector32, failures: Seq[Paym
8585
sealed trait PaymentRelayed extends PaymentEvent {
8686
val amountIn: MilliSatoshi
8787
val amountOut: MilliSatoshi
88-
val startedAt: TimestampMilli
88+
val receivedAt: TimestampMilli
8989
val settledAt: TimestampMilli
9090
}
9191

92-
case class ChannelPaymentRelayed(amountIn: MilliSatoshi, amountOut: MilliSatoshi, paymentHash: ByteVector32, fromChannelId: ByteVector32, toChannelId: ByteVector32, startedAt: TimestampMilli, settledAt: TimestampMilli) extends PaymentRelayed {
92+
case class ChannelPaymentRelayed(amountIn: MilliSatoshi, amountOut: MilliSatoshi, paymentHash: ByteVector32, fromChannelId: ByteVector32, toChannelId: ByteVector32, receivedAt: TimestampMilli, settledAt: TimestampMilli) extends PaymentRelayed {
9393
override val timestamp: TimestampMilli = settledAt
9494
}
9595

9696
case class TrampolinePaymentRelayed(paymentHash: ByteVector32, incoming: PaymentRelayed.Incoming, outgoing: PaymentRelayed.Outgoing, nextTrampolineNodeId: PublicKey, nextTrampolineAmount: MilliSatoshi) extends PaymentRelayed {
9797
override val amountIn: MilliSatoshi = incoming.map(_.amount).sum
9898
override val amountOut: MilliSatoshi = outgoing.map(_.amount).sum
99-
override val startedAt: TimestampMilli = incoming.map(_.receivedAt).minOption.getOrElse(TimestampMilli.now())
99+
override val receivedAt: TimestampMilli = incoming.map(_.receivedAt).minOption.getOrElse(TimestampMilli.now())
100100
override val settledAt: TimestampMilli = outgoing.map(_.settledAt).maxOption.getOrElse(TimestampMilli.now())
101101
override val timestamp: TimestampMilli = settledAt
102102
}
103103

104104
case class OnTheFlyFundingPaymentRelayed(paymentHash: ByteVector32, incoming: PaymentRelayed.Incoming, outgoing: PaymentRelayed.Outgoing) extends PaymentRelayed {
105105
override val amountIn: MilliSatoshi = incoming.map(_.amount).sum
106106
override val amountOut: MilliSatoshi = outgoing.map(_.amount).sum
107-
override val startedAt: TimestampMilli = incoming.map(_.receivedAt).minOption.getOrElse(TimestampMilli.now())
107+
override val receivedAt: TimestampMilli = incoming.map(_.receivedAt).minOption.getOrElse(TimestampMilli.now())
108108
override val settledAt: TimestampMilli = outgoing.map(_.settledAt).maxOption.getOrElse(TimestampMilli.now())
109109
override val timestamp: TimestampMilli = settledAt
110110
}

eclair-core/src/main/scala/fr/acinq/eclair/payment/PaymentPacket.scala

Lines changed: 13 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,9 @@ import scala.util.{Failure, Success}
3636
* Created by t-bast on 08/10/2019.
3737
*/
3838

39-
sealed trait IncomingPaymentPacket
39+
sealed trait IncomingPaymentPacket {
40+
def receivedAt: TimestampMilli
41+
}
4042

4143
/** Helpers to handle incoming payment packets. */
4244
object IncomingPaymentPacket {
@@ -47,7 +49,7 @@ object IncomingPaymentPacket {
4749
/** We are an intermediate node. */
4850
sealed trait RelayPacket extends IncomingPaymentPacket
4951
/** We must relay the payment to a direct peer. */
50-
case class ChannelRelayPacket(add: UpdateAddHtlc, payload: IntermediatePayload.ChannelRelay, nextPacket: OnionRoutingPacket) extends RelayPacket {
52+
case class ChannelRelayPacket(add: UpdateAddHtlc, payload: IntermediatePayload.ChannelRelay, nextPacket: OnionRoutingPacket, receivedAt: TimestampMilli) extends RelayPacket {
5153
val amountToForward: MilliSatoshi = payload.amountToForward(add.amountMsat)
5254
val outgoingCltv: CltvExpiry = payload.outgoingCltv(add.cltvExpiry)
5355
val relayFeeMsat: MilliSatoshi = add.amountMsat - amountToForward
@@ -59,9 +61,9 @@ object IncomingPaymentPacket {
5961
def outerPayload: FinalPayload.Standard
6062
def innerPayload: IntermediatePayload.NodeRelay
6163
}
62-
case class RelayToTrampolinePacket(add: UpdateAddHtlc, outerPayload: FinalPayload.Standard, innerPayload: IntermediatePayload.NodeRelay.Standard, nextPacket: OnionRoutingPacket) extends NodeRelayPacket
63-
case class RelayToNonTrampolinePacket(add: UpdateAddHtlc, outerPayload: FinalPayload.Standard, innerPayload: IntermediatePayload.NodeRelay.ToNonTrampoline) extends NodeRelayPacket
64-
case class RelayToBlindedPathsPacket(add: UpdateAddHtlc, outerPayload: FinalPayload.Standard, innerPayload: IntermediatePayload.NodeRelay.ToBlindedPaths) extends NodeRelayPacket
64+
case class RelayToTrampolinePacket(add: UpdateAddHtlc, outerPayload: FinalPayload.Standard, innerPayload: IntermediatePayload.NodeRelay.Standard, nextPacket: OnionRoutingPacket, receivedAt: TimestampMilli) extends NodeRelayPacket
65+
case class RelayToNonTrampolinePacket(add: UpdateAddHtlc, outerPayload: FinalPayload.Standard, innerPayload: IntermediatePayload.NodeRelay.ToNonTrampoline, receivedAt: TimestampMilli) extends NodeRelayPacket
66+
case class RelayToBlindedPathsPacket(add: UpdateAddHtlc, outerPayload: FinalPayload.Standard, innerPayload: IntermediatePayload.NodeRelay.ToBlindedPaths, receivedAt: TimestampMilli) extends NodeRelayPacket
6567
// @formatter:on
6668

6769
case class DecodedOnionPacket(payload: TlvStream[OnionPaymentPayloadTlv], next_opt: Option[OnionRoutingPacket])
@@ -135,15 +137,15 @@ object IncomingPaymentPacket {
135137
decryptEncryptedRecipientData(add, privateKey, payload, encrypted.data).flatMap {
136138
case DecodedEncryptedRecipientData(blindedPayload, nextPathKey) =>
137139
validateBlindedChannelRelayPayload(add, payload, blindedPayload, nextPathKey, nextPacket).flatMap {
138-
case ChannelRelayPacket(_, payload, nextPacket) if payload.outgoing == Right(ShortChannelId.toSelf) =>
140+
case ChannelRelayPacket(_, payload, nextPacket, _) if payload.outgoing == Right(ShortChannelId.toSelf) =>
139141
decrypt(add.copy(onionRoutingPacket = nextPacket, tlvStream = add.tlvStream.copy(records = Set(UpdateAddHtlcTlv.PathKey(nextPathKey)))), privateKey, features)
140142
case relayPacket => Right(relayPacket)
141143
}
142144
}
143145
case None if add.pathKey_opt.isDefined => Left(InvalidOnionBlinding(Sphinx.hash(add.onionRoutingPacket)))
144146
case None =>
145147
// We are not inside a blinded path: channel relay information is directly available.
146-
IntermediatePayload.ChannelRelay.Standard.validate(payload).left.map(_.failureMessage).map(payload => ChannelRelayPacket(add, payload, nextPacket))
148+
IntermediatePayload.ChannelRelay.Standard.validate(payload).left.map(_.failureMessage).map(payload => ChannelRelayPacket(add, payload, nextPacket, TimestampMilli.now()))
147149
}
148150
case DecodedOnionPacket(payload, None) =>
149151
// We are the final node for the outer onion, so we are either:
@@ -216,7 +218,7 @@ object IncomingPaymentPacket {
216218
case payload if add.amountMsat < payload.paymentRelayData.paymentConstraints.minAmount => Left(InvalidOnionBlinding(Sphinx.hash(add.onionRoutingPacket)))
217219
case payload if add.cltvExpiry > payload.paymentRelayData.paymentConstraints.maxCltvExpiry => Left(InvalidOnionBlinding(Sphinx.hash(add.onionRoutingPacket)))
218220
case payload if !Features.areCompatible(Features.empty, payload.paymentRelayData.allowedFeatures) => Left(InvalidOnionBlinding(Sphinx.hash(add.onionRoutingPacket)))
219-
case payload => Right(ChannelRelayPacket(add, payload, nextPacket))
221+
case payload => Right(ChannelRelayPacket(add, payload, nextPacket, TimestampMilli.now()))
220222
}
221223
}
222224

@@ -261,7 +263,7 @@ object IncomingPaymentPacket {
261263
IntermediatePayload.NodeRelay.Standard.validate(innerPayload).left.map(_.failureMessage).flatMap {
262264
case _ if add.amountMsat < outerPayload.amount => Left(FinalIncorrectHtlcAmount(add.amountMsat))
263265
case _ if add.cltvExpiry != outerPayload.expiry => Left(FinalIncorrectCltvExpiry(add.cltvExpiry))
264-
case innerPayload => Right(RelayToTrampolinePacket(add, outerPayload, innerPayload, next))
266+
case innerPayload => Right(RelayToTrampolinePacket(add, outerPayload, innerPayload, next, TimestampMilli.now()))
265267
}
266268
}
267269
}
@@ -271,7 +273,7 @@ object IncomingPaymentPacket {
271273
IntermediatePayload.NodeRelay.ToNonTrampoline.validate(innerPayload).left.map(_.failureMessage).flatMap {
272274
case _ if add.amountMsat < outerPayload.amount => Left(FinalIncorrectHtlcAmount(add.amountMsat))
273275
case _ if add.cltvExpiry != outerPayload.expiry => Left(FinalIncorrectCltvExpiry(add.cltvExpiry))
274-
case innerPayload => Right(RelayToNonTrampolinePacket(add, outerPayload, innerPayload))
276+
case innerPayload => Right(RelayToNonTrampolinePacket(add, outerPayload, innerPayload, TimestampMilli.now()))
275277
}
276278
}
277279
}
@@ -281,7 +283,7 @@ object IncomingPaymentPacket {
281283
IntermediatePayload.NodeRelay.ToBlindedPaths.validate(innerPayload).left.map(_.failureMessage).flatMap {
282284
case _ if add.amountMsat < outerPayload.amount => Left(FinalIncorrectHtlcAmount(add.amountMsat))
283285
case _ if add.cltvExpiry != outerPayload.expiry => Left(FinalIncorrectCltvExpiry(add.cltvExpiry))
284-
case innerPayload => Right(RelayToBlindedPathsPacket(add, outerPayload, innerPayload))
286+
case innerPayload => Right(RelayToBlindedPathsPacket(add, outerPayload, innerPayload, TimestampMilli.now()))
285287
}
286288
}
287289
}

eclair-core/src/main/scala/fr/acinq/eclair/payment/relay/ChannelRelay.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -71,7 +71,7 @@ object ChannelRelay {
7171
parentPaymentId_opt = Some(relayId), // for a channel relay, parent payment id = relay id
7272
paymentHash_opt = Some(r.add.paymentHash),
7373
nodeAlias_opt = Some(nodeParams.alias))) {
74-
val upstream = Upstream.Hot.Channel(r.add.removeUnknownTlvs(), TimestampMilli.now(), originNode)
74+
val upstream = Upstream.Hot.Channel(r.add.removeUnknownTlvs(), r.receivedAt, originNode)
7575
val confidence = (r.add.endorsement + 0.5) / 8
7676
new ChannelRelay(nodeParams, register, channels, r, upstream, confidence, context).start()
7777
}
@@ -220,15 +220,15 @@ class ChannelRelay private(nodeParams: NodeParams,
220220
private def waitForAddSettled(): Behavior[Command] =
221221
Behaviors.receiveMessagePartial {
222222
case WrappedAddResponse(RES_ADD_SETTLED(_, htlc, fulfill: HtlcResult.Fulfill)) =>
223-
context.log.info("relaying fulfill to upstream, startedAt={}, endedAt={}, confidence={}, originNode={}, outgoingChannel={}", upstream.receivedAt, TimestampMilli.now(), confidence, upstream.receivedFrom, htlc.channelId)
223+
context.log.info("relaying fulfill to upstream, receivedAt={}, endedAt={}, confidence={}, originNode={}, outgoingChannel={}", upstream.receivedAt, r.receivedAt, confidence, upstream.receivedFrom, htlc.channelId)
224224
Metrics.relayFulfill(confidence)
225225
val cmd = CMD_FULFILL_HTLC(upstream.add.id, fulfill.paymentPreimage, commit = true)
226-
context.system.eventStream ! EventStream.Publish(ChannelPaymentRelayed(upstream.amountIn, htlc.amountMsat, htlc.paymentHash, upstream.add.channelId, htlc.channelId, upstream.receivedAt, TimestampMilli.now()))
226+
context.system.eventStream ! EventStream.Publish(ChannelPaymentRelayed(upstream.amountIn, htlc.amountMsat, htlc.paymentHash, upstream.add.channelId, htlc.channelId, upstream.receivedAt, r.receivedAt))
227227
recordRelayDuration(isSuccess = true)
228228
safeSendAndStop(upstream.add.channelId, cmd)
229229

230230
case WrappedAddResponse(RES_ADD_SETTLED(_, htlc, fail: HtlcResult.Fail)) =>
231-
context.log.info("relaying fail to upstream, startedAt={}, endedAt={}, confidence={}, originNode={}, outgoingChannel={}", upstream.receivedAt, TimestampMilli.now(), confidence, upstream.receivedFrom, htlc.channelId)
231+
context.log.info("relaying fail to upstream, receivedAt={}, endedAt={}, confidence={}, originNode={}, outgoingChannel={}", upstream.receivedAt, r.receivedAt, confidence, upstream.receivedFrom, htlc.channelId)
232232
Metrics.relayFail(confidence)
233233
Metrics.recordPaymentRelayFailed(Tags.FailureType.Remote, Tags.RelayType.Channel)
234234
val cmd = translateRelayFailure(upstream.add.id, fail, Some(upstream.receivedAt))

eclair-core/src/main/scala/fr/acinq/eclair/payment/relay/NodeRelay.scala

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ object NodeRelay {
107107
}.toClassic
108108
val incomingPaymentHandler = context.actorOf(MultiPartPaymentFSM.props(nodeParams, paymentHash, totalAmountIn, mppFsmAdapters))
109109
val nextPacket_opt = nodeRelayPacket match {
110-
case IncomingPaymentPacket.RelayToTrampolinePacket(_, _, _, nextPacket) => Some(nextPacket)
110+
case IncomingPaymentPacket.RelayToTrampolinePacket(_, _, _, nextPacket, _) => Some(nextPacket)
111111
case _: IncomingPaymentPacket.RelayToNonTrampolinePacket => None
112112
case _: IncomingPaymentPacket.RelayToBlindedPathsPacket => None
113113
}
@@ -223,8 +223,8 @@ class NodeRelay private(nodeParams: NodeParams,
223223
case Relay(packet: IncomingPaymentPacket.NodeRelayPacket, originNode) =>
224224
require(packet.outerPayload.paymentSecret == paymentSecret, "payment secret mismatch")
225225
context.log.debug("forwarding incoming htlc #{} from channel {} to the payment FSM", packet.add.id, packet.add.channelId)
226-
handler ! MultiPartPaymentFSM.HtlcPart(packet.outerPayload.totalAmount, packet.add, TimestampMilli.now())
227-
receiving(htlcs :+ Upstream.Hot.Channel(packet.add.removeUnknownTlvs(), TimestampMilli.now(), originNode), nextPayload, nextPacket_opt, handler)
226+
handler ! MultiPartPaymentFSM.HtlcPart(packet.outerPayload.totalAmount, packet.add, packet.receivedAt)
227+
receiving(htlcs :+ Upstream.Hot.Channel(packet.add.removeUnknownTlvs(), packet.receivedAt, originNode), nextPayload, nextPacket_opt, handler)
228228
case WrappedMultiPartPaymentFailed(MultiPartPaymentFSM.MultiPartPaymentFailed(_, failure, parts)) =>
229229
context.log.warn("could not complete incoming multi-part payment (parts={} paidAmount={} failure={})", parts.size, parts.map(_.amount).sum, failure)
230230
Metrics.recordPaymentRelayFailed(failure.getClass.getSimpleName, Tags.RelayType.Trampoline)
@@ -464,7 +464,7 @@ class NodeRelay private(nodeParams: NodeParams,
464464

465465
private def rejectExtraHtlcPartialFunction: PartialFunction[Command, Behavior[Command]] = {
466466
case Relay(nodeRelayPacket, _) =>
467-
rejectExtraHtlc(nodeRelayPacket.add, TimestampMilli.now())
467+
rejectExtraHtlc(nodeRelayPacket.add, nodeRelayPacket.receivedAt)
468468
Behaviors.same
469469
// NB: this message would be sent from the payment FSM which we stopped before going to this state, but all this is asynchronous.
470470
// We always fail extraneous HTLCs. They are a spec violation from the sender, but harmless in the relay case.

eclair-core/src/main/scala/fr/acinq/eclair/payment/relay/Relayer.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ class Relayer(nodeParams: NodeParams, router: ActorRef, register: ActorRef, paym
7373
case Right(r: IncomingPaymentPacket.NodeRelayPacket) =>
7474
if (!nodeParams.enableTrampolinePayment) {
7575
log.warning(s"rejecting htlc #${add.id} from channelId=${add.channelId} reason=trampoline disabled")
76-
PendingCommandsDb.safeSend(register, nodeParams.db.pendingCommands, add.channelId, CMD_FAIL_HTLC(add.id, FailureReason.LocalFailure(RequiredNodeFeatureMissing()), Some(TimestampMilli.now()), commit = true))
76+
PendingCommandsDb.safeSend(register, nodeParams.db.pendingCommands, add.channelId, CMD_FAIL_HTLC(add.id, FailureReason.LocalFailure(RequiredNodeFeatureMissing()), Some(r.receivedAt), commit = true))
7777
} else {
7878
nodeRelayer ! NodeRelayer.Relay(r, originNode)
7979
}

eclair-core/src/main/scala/fr/acinq/eclair/wire/protocol/LightningMessageTypes.scala

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,6 @@ import scodec.bits.ByteVector
2929

3030
import java.net.{Inet4Address, Inet6Address, InetAddress}
3131
import java.nio.charset.StandardCharsets
32-
import scala.concurrent.duration.FiniteDuration
3332
import scala.util.Try
3433

3534
/**

eclair-core/src/test/scala/fr/acinq/eclair/channel/ChannelDataSpec.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import fr.acinq.eclair.channel.states.{ChannelStateTestsBase, ChannelStateTestsT
2525
import fr.acinq.eclair.crypto.keymanager.ChannelKeys
2626
import fr.acinq.eclair.transactions.Transactions._
2727
import fr.acinq.eclair.wire.protocol.{CommitSig, FailureReason, RevokeAndAck, UnknownNextPeer, UpdateAddHtlc}
28-
import fr.acinq.eclair.{CltvExpiryDelta, MilliSatoshiLong, NodeParams, TestKitBaseClass, TimestampMilli}
28+
import fr.acinq.eclair.{CltvExpiryDelta, MilliSatoshiLong, NodeParams, TestKitBaseClass}
2929
import org.scalatest.funsuite.AnyFunSuiteLike
3030
import scodec.bits.ByteVector
3131

eclair-core/src/test/scala/fr/acinq/eclair/channel/states/e/OfflineStateSpec.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ import fr.acinq.eclair.channel.states.ChannelStateTestsBase.PimpTestFSM
3434
import fr.acinq.eclair.channel.states.{ChannelStateTestsBase, ChannelStateTestsTags}
3535
import fr.acinq.eclair.transactions.Transactions.HtlcSuccessTx
3636
import fr.acinq.eclair.wire.protocol._
37-
import fr.acinq.eclair.{BlockHeight, CltvExpiry, CltvExpiryDelta, MilliSatoshiLong, TestConstants, TestKitBaseClass, TestUtils, TimestampMilli, randomBytes32}
37+
import fr.acinq.eclair.{BlockHeight, CltvExpiry, CltvExpiryDelta, MilliSatoshiLong, TestConstants, TestKitBaseClass, TestUtils, randomBytes32}
3838
import org.scalatest.funsuite.FixtureAnyFunSuiteLike
3939
import org.scalatest.{Outcome, Tag}
4040

eclair-core/src/test/scala/fr/acinq/eclair/channel/states/f/ShutdownStateSpec.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ import fr.acinq.eclair.payment._
3333
import fr.acinq.eclair.payment.relay.Relayer._
3434
import fr.acinq.eclair.payment.send.SpontaneousRecipient
3535
import fr.acinq.eclair.wire.protocol.{AnnouncementSignatures, ChannelUpdate, ClosingSigned, CommitSig, Error, FailureMessageCodecs, FailureReason, PermanentChannelFailure, RevokeAndAck, Shutdown, UpdateAddHtlc, UpdateFailHtlc, UpdateFailMalformedHtlc, UpdateFee, UpdateFulfillHtlc}
36-
import fr.acinq.eclair.{BlockHeight, CltvExpiry, CltvExpiryDelta, MilliSatoshiLong, TestConstants, TestKitBaseClass, TimestampMilli, randomBytes32, randomKey}
36+
import fr.acinq.eclair.{BlockHeight, CltvExpiry, CltvExpiryDelta, MilliSatoshiLong, TestConstants, TestKitBaseClass, randomBytes32, randomKey}
3737
import org.scalatest.Inside.inside
3838
import org.scalatest.funsuite.FixtureAnyFunSuiteLike
3939
import org.scalatest.{Outcome, Tag}

0 commit comments

Comments
 (0)