Skip to content

Commit

Permalink
Update InvalidOnionPayload.
Browse files Browse the repository at this point in the history
It should simply be a PERM failure.
The spec hasn't decided yet to assign it a specific failure code.
  • Loading branch information
t-bast committed Aug 29, 2019
1 parent 000913b commit f235d97
Show file tree
Hide file tree
Showing 4 changed files with 15 additions and 24 deletions.
10 changes: 7 additions & 3 deletions eclair-core/src/main/scala/fr/acinq/eclair/payment/Relayer.scala
Original file line number Diff line number Diff line change
Expand Up @@ -119,11 +119,15 @@ class Relayer(nodeParams: NodeParams, register: ActorRef, paymentHandler: ActorR
log.info(s"forwarding htlc #${add.id} paymentHash=${add.paymentHash} from channelId=${add.channelId} to shortChannelId=$selectedShortChannelId")
register ! Register.ForwardShortId(selectedShortChannelId, cmdAdd)
}
case Left(badOnion) =>
case Left(badOnion: BadOnion) =>
log.warning(s"couldn't parse onion: reason=${badOnion.message}")
val cmdFail = CMD_FAIL_MALFORMED_HTLC(add.id, badOnion.onionHash, FailureMessageCodecs.failureCode(badOnion), commit = true)
log.info(s"rejecting htlc #${add.id} paymentHash=${add.paymentHash} from channelId=${add.channelId} reason=malformed onionHash=${cmdFail.onionHash} failureCode=${cmdFail.failureCode}")
commandBuffer ! CommandBuffer.CommandSend(add.channelId, add.id, cmdFail)
case Left(failure) =>
log.warning(s"couldn't process onion: reason=${failure.message}")
val cmdFail = CMD_FAIL_HTLC(add.id, Right(failure), commit = true)
commandBuffer ! CommandBuffer.CommandSend(add.channelId, add.id, cmdFail)
}

case Status.Failure(Register.ForwardShortIdFailure(Register.ForwardShortId(shortChannelId, CMD_ADD_HTLC(_, _, _, _, Right(add), _, _)))) =>
Expand Down Expand Up @@ -229,12 +233,12 @@ object Relayer extends Logging {
* @param privateKey this node's private key
* @return the payload for the next hop or an error.
*/
def decryptPacket(add: UpdateAddHtlc, privateKey: PrivateKey, features: ByteVector): Either[BadOnion, NextPayload] =
def decryptPacket(add: UpdateAddHtlc, privateKey: PrivateKey, features: ByteVector): Either[FailureMessage, NextPayload] =
Sphinx.PaymentPacket.peel(privateKey, add.paymentHash, add.onionRoutingPacket) match {
case Right(p@Sphinx.DecryptedPacket(payload, nextPacket, _)) =>
OnionCodecs.perHopPayloadCodec.decode(payload.bits) match {
case Attempt.Successful(DecodeResult(OnionPerHopPayload(Left(_)), _)) if !Features.hasVariableLengthOnion(features) =>
Left(InvalidOnionPayload(Sphinx.PaymentPacket.hash(add.onionRoutingPacket)))
Left(InvalidRealm)
case Attempt.Successful(DecodeResult(perHopPayload, remainder)) =>
if (remainder.nonEmpty) {
logger.warn(s"${remainder.length} bits remaining after per-hop payload decoding: there might be an issue with the onion codec")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,6 @@ case object RequiredNodeFeatureMissing extends Perm with Node { def message = "p
case class InvalidOnionVersion(onionHash: ByteVector32) extends BadOnion with Perm { def message = "onion version was not understood by the processing node" }
case class InvalidOnionHmac(onionHash: ByteVector32) extends BadOnion with Perm { def message = "onion HMAC was incorrect when it reached the processing node" }
case class InvalidOnionKey(onionHash: ByteVector32) extends BadOnion with Perm { def message = "ephemeral key was unparsable by the processing node" }
case class InvalidOnionPayload(onionHash: ByteVector32) extends BadOnion with Perm { def message = "onion per-hop payload could not be parsed" }
case class TemporaryChannelFailure(update: ChannelUpdate) extends Update { def message = s"channel ${update.shortChannelId} is currently unavailable" }
case object PermanentChannelFailure extends Perm { def message = "channel is permanently unavailable" }
case object RequiredChannelFeatureMissing extends Perm { def message = "channel requires features not present in the onion" }
Expand All @@ -59,6 +58,7 @@ case object FinalExpiryTooSoon extends FailureMessage { def message = "payment e
case class FinalIncorrectCltvExpiry(expiry: CltvExpiry) extends FailureMessage { def message = "payment expiry doesn't match the value in the onion" }
case class FinalIncorrectHtlcAmount(amount: MilliSatoshi) extends FailureMessage { def message = "payment amount is incorrect in the final htlc" }
case object ExpiryTooFar extends FailureMessage { def message = "payment expiry is too far in the future" }
case class InvalidOnionPayload(onionHash: ByteVector32) extends Perm { def message = "onion per-hop payload is invalid" }
// @formatter:on

object FailureMessageCodecs {
Expand All @@ -78,7 +78,6 @@ object FailureMessageCodecs {
.typecase(NODE | 2, provide(TemporaryNodeFailure))
.typecase(PERM | 2, provide(PermanentNodeFailure))
.typecase(PERM | NODE | 3, provide(RequiredNodeFeatureMissing))
.typecase(BADONION | PERM, sha256.as[InvalidOnionPayload])
.typecase(BADONION | PERM | 4, sha256.as[InvalidOnionVersion])
.typecase(BADONION | PERM | 5, sha256.as[InvalidOnionHmac])
.typecase(BADONION | PERM | 6, sha256.as[InvalidOnionKey])
Expand All @@ -97,6 +96,7 @@ object FailureMessageCodecs {
.typecase(18, ("expiry" | cltvExpiry).as[FinalIncorrectCltvExpiry])
.typecase(19, ("amountMsat" | millisatoshi).as[FinalIncorrectHtlcAmount])
.typecase(21, provide(ExpiryTooFar))
.typecase(PERM, sha256.as[InvalidOnionPayload])

/**
* Return the failure code for a given failure message. This method actually encodes the failure message, which is a
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -308,11 +308,7 @@ class RelayerSpec extends TestkitBaseClass {
val add_ab = UpdateAddHtlc(channelId_ab, 123456, amount_ab, paymentHash, expiry_ab, onion)
sender.send(relayer, ForwardAdd(add_ab))

val fail = register.expectMsgType[Register.Forward[CMD_FAIL_MALFORMED_HTLC]].message
assert(fail.id === add_ab.id)
assert(fail.onionHash == Sphinx.PaymentPacket.hash(add_ab.onionRoutingPacket))
assert(fail.failureCode === (FailureMessageCodecs.BADONION | FailureMessageCodecs.PERM))

register.expectMsg(Register.Forward(channelId_ab, CMD_FAIL_HTLC(add_ab.id, Right(InvalidOnionPayload(Sphinx.PaymentPacket.hash(add_ab.onionRoutingPacket))), commit = true)))
register.expectNoMsg(100 millis)
paymentHandler.expectNoMsg(100 millis)
}
Expand All @@ -333,11 +329,7 @@ class RelayerSpec extends TestkitBaseClass {
val add_ab = UpdateAddHtlc(channelId_ab, 123456, amount_ab, paymentHash, expiry_ab, onion)
sender.send(relayer, ForwardAdd(add_ab))

val fail = register.expectMsgType[Register.Forward[CMD_FAIL_MALFORMED_HTLC]].message
assert(fail.id === add_ab.id)
assert(fail.onionHash == Sphinx.PaymentPacket.hash(add_ab.onionRoutingPacket))
assert(fail.failureCode === (FailureMessageCodecs.BADONION | FailureMessageCodecs.PERM))

register.expectMsg(Register.Forward(channelId_ab, CMD_FAIL_HTLC(add_ab.id, Right(InvalidRealm), commit = true)))
register.expectNoMsg(100 millis)
paymentHandler.expectNoMsg(100 millis)
}
Expand Down Expand Up @@ -460,11 +452,7 @@ class RelayerSpec extends TestkitBaseClass {
val add_ab = UpdateAddHtlc(channelId_ab, 123456, amount_ab, paymentHash, expiry_ab, onion)
sender.send(relayer, ForwardAdd(add_ab))

val fail = register.expectMsgType[Register.Forward[CMD_FAIL_MALFORMED_HTLC]].message
assert(fail.id === add_ab.id)
assert(fail.onionHash == Sphinx.PaymentPacket.hash(add_ab.onionRoutingPacket))
assert(fail.failureCode === (FailureMessageCodecs.BADONION | FailureMessageCodecs.PERM))

register.expectMsg(Register.Forward(channelId_ab, CMD_FAIL_HTLC(add_ab.id, Right(InvalidOnionPayload(Sphinx.PaymentPacket.hash(add_ab.onionRoutingPacket))), commit = true)))
register.expectNoMsg(100 millis)
paymentHandler.expectNoMsg(100 millis)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -44,10 +44,10 @@ class FailureMessageCodecsSpec extends FunSuite {
test("encode/decode all channel messages") {
val msgs: List[FailureMessage] =
InvalidRealm :: TemporaryNodeFailure :: PermanentNodeFailure :: RequiredNodeFeatureMissing ::
InvalidOnionVersion(randomBytes32) :: InvalidOnionHmac(randomBytes32) :: InvalidOnionKey(randomBytes32) :: InvalidOnionPayload(randomBytes32) ::
InvalidOnionVersion(randomBytes32) :: InvalidOnionHmac(randomBytes32) :: InvalidOnionKey(randomBytes32) ::
TemporaryChannelFailure(channelUpdate) :: PermanentChannelFailure :: RequiredChannelFeatureMissing :: UnknownNextPeer ::
AmountBelowMinimum(123456 msat, channelUpdate) :: FeeInsufficient(546463 msat, channelUpdate) :: IncorrectCltvExpiry(CltvExpiry(1211), channelUpdate) :: ExpiryTooSoon(channelUpdate) ::
IncorrectOrUnknownPaymentDetails(123456 msat) :: IncorrectPaymentAmount :: FinalExpiryTooSoon :: FinalIncorrectCltvExpiry(CltvExpiry(1234)) :: ChannelDisabled(0, 1, channelUpdate) :: ExpiryTooFar :: Nil
IncorrectOrUnknownPaymentDetails(123456 msat) :: IncorrectPaymentAmount :: FinalExpiryTooSoon :: FinalIncorrectCltvExpiry(CltvExpiry(1234)) :: ChannelDisabled(0, 1, channelUpdate) :: ExpiryTooFar :: InvalidOnionPayload(randomBytes32) :: Nil

msgs.foreach {
msg => {
Expand All @@ -62,8 +62,7 @@ class FailureMessageCodecsSpec extends FunSuite {
val msgs = Map(
(BADONION | PERM | 4) -> InvalidOnionVersion(randomBytes32),
(BADONION | PERM | 5) -> InvalidOnionHmac(randomBytes32),
(BADONION | PERM | 6) -> InvalidOnionKey(randomBytes32),
(BADONION | PERM) -> InvalidOnionPayload(randomBytes32)
(BADONION | PERM | 6) -> InvalidOnionKey(randomBytes32)
)

for ((code, message) <- msgs) {
Expand Down

0 comments on commit f235d97

Please sign in to comment.