Skip to content

Commit 962c63c

Browse files
committed
Test
1 parent 70fdfb3 commit 962c63c

File tree

3 files changed

+35
-3
lines changed

3 files changed

+35
-3
lines changed

eclair-core/src/main/scala/fr/acinq/eclair/crypto/Sphinx.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -385,7 +385,7 @@ object Sphinx extends Logging {
385385
val previousAttribution = previousAttribution_opt.getOrElse(ByteVector.low(920))
386386
val previousHmacs = getHmacs(previousAttribution).dropRight(1).map(_.drop(1))
387387
val mac = Hmac256(generateKey("um", sharedSecret))
388-
val holdTimes = uint32.encode(holdTime.toMillis).require.bytes ++ previousAttribution.take(19 * 4)
388+
val holdTimes = uint32.encode(holdTime.toMillis).map(_.bytes).getOrElse(ByteVector.high(4)) ++ previousAttribution.take(19 * 4)
389389
val hmacs = computeHmacs(mac, reason, holdTimes, previousHmacs, 0) +: previousHmacs
390390
cipher(holdTimes ++ ByteVector.concat(hmacs.map(ByteVector.concat(_))), sharedSecret)
391391
}

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

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -374,14 +374,14 @@ object OutgoingPaymentPacket {
374374
}
375375
}
376376

377-
def buildHtlcFailure(nodeSecret: PrivateKey, useAttributableFailures: Boolean, cmd: CMD_FAIL_HTLC, add: UpdateAddHtlc): Either[CannotExtractSharedSecret, HtlcFailureMessage] = {
377+
def buildHtlcFailure(nodeSecret: PrivateKey, useAttributableFailures: Boolean, cmd: CMD_FAIL_HTLC, add: UpdateAddHtlc, now: TimestampMilli = TimestampMilli.now()): Either[CannotExtractSharedSecret, HtlcFailureMessage] = {
378378
add.pathKey_opt match {
379379
case Some(_) =>
380380
// We are part of a blinded route and we're not the introduction node.
381381
val failure = InvalidOnionBlinding(Sphinx.hash(add.onionRoutingPacket))
382382
Right(UpdateFailMalformedHtlc(add.channelId, add.id, failure.onionHash, failure.code))
383383
case None =>
384-
val holdTime = TimestampMilli.now() - cmd.startHoldTime
384+
val holdTime = now - cmd.startHoldTime
385385
buildHtlcFailure(nodeSecret, useAttributableFailures, cmd.reason, add, holdTime).map {
386386
case (encryptedReason, tlvs) => UpdateFailHtlc(add.channelId, cmd.id, encryptedReason, tlvs)
387387
}

eclair-core/src/test/scala/fr/acinq/eclair/payment/PaymentPacketSpec.scala

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,7 @@ import fr.acinq.eclair.TestUtils.randomTxId
2525
import fr.acinq.eclair.channel.ChannelSpendSignature.IndividualSignature
2626
import fr.acinq.eclair.channel._
2727
import fr.acinq.eclair.channel.fsm.Channel
28+
import fr.acinq.eclair.crypto.Sphinx.HoldTime
2829
import fr.acinq.eclair.crypto.{ShaChain, Sphinx}
2930
import fr.acinq.eclair.payment.IncomingPaymentPacket._
3031
import fr.acinq.eclair.payment.OutgoingPaymentPacket._
@@ -671,6 +672,37 @@ class PaymentPacketSpec extends AnyFunSuite with BeforeAndAfterAll {
671672
assert(decryptedFailure == failure)
672673
}
673674

675+
test("build htlc failure onion with attribution data") {
676+
// a -> b -> c -> d -> e
677+
val recipient = ClearRecipient(e, Features.empty, finalAmount, finalExpiry, paymentSecret)
678+
val Right(payment) = buildOutgoingPayment(TestConstants.emptyOrigin, paymentHash, Route(finalAmount, hops, None), recipient, 1.0)
679+
val add_b = UpdateAddHtlc(randomBytes32(), 0, amount_ab, paymentHash, expiry_ab, payment.cmd.onion, None, 1.0, None)
680+
val Right(ChannelRelayPacket(_, _, packet_c)) = decrypt(add_b, priv_b.privateKey, Features.empty)
681+
val add_c = UpdateAddHtlc(randomBytes32(), 1, amount_bc, paymentHash, expiry_bc, packet_c, None, 1.0, None)
682+
val Right(ChannelRelayPacket(_, _, packet_d)) = decrypt(add_c, priv_c.privateKey, Features.empty)
683+
val add_d = UpdateAddHtlc(randomBytes32(), 2, amount_cd, paymentHash, expiry_cd, packet_d, None, 1.0, None)
684+
val Right(ChannelRelayPacket(_, _, packet_e)) = decrypt(add_d, priv_d.privateKey, Features.empty)
685+
val add_e = UpdateAddHtlc(randomBytes32(), 3, amount_de, paymentHash, expiry_de, packet_e, None, 1.0, None)
686+
val Right(FinalPacket(_, payload_e)) = decrypt(add_e, priv_e.privateKey, Features.empty)
687+
assert(payload_e.isInstanceOf[FinalPayload.Standard])
688+
689+
// e returns a failure
690+
val failure = IncorrectOrUnknownPaymentDetails(finalAmount, BlockHeight(currentBlockCount))
691+
val Right(fail_e: UpdateFailHtlc) = buildHtlcFailure(priv_e.privateKey, useAttributableFailures = true, CMD_FAIL_HTLC(add_e.id, FailureReason.LocalFailure(failure), TimestampMilli(60)), add_e, now = TimestampMilli(62))
692+
assert(fail_e.id == add_e.id)
693+
val Right(fail_d: UpdateFailHtlc) = buildHtlcFailure(priv_d.privateKey, useAttributableFailures = true, CMD_FAIL_HTLC(add_d.id, FailureReason.EncryptedDownstreamFailure(fail_e.reason, fail_e.attribution_opt), TimestampMilli(25)), add_d, now = TimestampMilli(63))
694+
assert(fail_d.id == add_d.id)
695+
val Right(fail_c: UpdateFailHtlc) = buildHtlcFailure(priv_c.privateKey, useAttributableFailures = true, CMD_FAIL_HTLC(add_c.id, FailureReason.EncryptedDownstreamFailure(fail_d.reason, fail_d.attribution_opt), TimestampMilli(10)), add_c, now = TimestampMilli(70))
696+
assert(fail_c.id == add_c.id)
697+
val Right(fail_b: UpdateFailHtlc) = buildHtlcFailure(priv_b.privateKey, useAttributableFailures = true, CMD_FAIL_HTLC(add_b.id, FailureReason.EncryptedDownstreamFailure(fail_c.reason, fail_c.attribution_opt), TimestampMilli(0)), add_b, now = TimestampMilli(76))
698+
assert(fail_b.id == add_b.id)
699+
val htlcFailure = Sphinx.FailurePacket.decrypt(fail_b.reason, fail_b.attribution_opt, payment.sharedSecrets)
700+
assert(htlcFailure.holdTimes == Seq(HoldTime(76 milliseconds, b), HoldTime(60 milliseconds, c), HoldTime(38 milliseconds, d), HoldTime(2 milliseconds, e)))
701+
val Right(Sphinx.DecryptedFailurePacket(failingNode, decryptedFailure)) = htlcFailure.failure
702+
assert(failingNode == e)
703+
assert(decryptedFailure == failure)
704+
}
705+
674706
test("build htlc failure onion (blinded payment)") {
675707
// a -> b -> c -> d -> e, blinded after c
676708
val (_, route, recipient) = longBlindedHops(hex"0451")

0 commit comments

Comments
 (0)