1
0
mirror of https://github.com/ACINQ/eclair.git synced 2024-11-20 10:39:19 +01:00

Fix encoding of failure messages (#366)

* Fix encoding of failure messages (fixes #363)
When a failure message includes a channel update field, this field must be encoded as:
[ len | channel update] and we did not include the len field.

* add `ExpiryTooFar` failure message
This commit is contained in:
Fabrice Drouin 2018-01-11 12:08:46 +01:00 committed by Pierre-Marie Padiou
parent 0781eb7a40
commit 065de8bb5c
2 changed files with 26 additions and 15 deletions

View File

@ -39,6 +39,7 @@ case object IncorrectPaymentAmount extends Perm
case object FinalExpiryTooSoon extends FailureMessage
case class FinalIncorrectCltvExpiry(expiry: Long) extends FailureMessage
case class FinalIncorrectHtlcAmount(amountMsat: Long) extends FailureMessage
case object ExpiryTooFar extends FailureMessage
// @formatter:on
object FailureMessageCodecs {
@ -49,6 +50,8 @@ object FailureMessageCodecs {
val sha256Codec: Codec[BinaryData] = ("sha256Codec" | binarydata(32))
val channelUpdateWithLengthCodec = variableSizeBytes(uint16, channelUpdateCodec)
val failureMessageCodec = discriminated[FailureMessage].by(uint16)
.typecase(PERM | 1, provide(InvalidRealm))
.typecase(NODE | 2, provide(TemporaryNodeFailure))
@ -57,18 +60,19 @@ object FailureMessageCodecs {
.typecase(BADONION | PERM | 4, sha256Codec.as[InvalidOnionVersion])
.typecase(BADONION | PERM | 5, sha256Codec.as[InvalidOnionHmac])
.typecase(BADONION | PERM | 6, sha256Codec.as[InvalidOnionKey])
.typecase(UPDATE | 7, (("channelUpdate" | channelUpdateCodec)).as[TemporaryChannelFailure])
.typecase(UPDATE | 7, (("channelUpdate" | channelUpdateWithLengthCodec)).as[TemporaryChannelFailure])
.typecase(PERM | 8, provide(PermanentChannelFailure))
.typecase(PERM | 9, provide(RequiredChannelFeatureMissing))
.typecase(PERM | 10, provide(UnknownNextPeer))
.typecase(UPDATE | 11, (("amountMsat" | uint64) :: ("channelUpdate" | channelUpdateCodec)).as[AmountBelowMinimum])
.typecase(UPDATE | 12, (("amountMsat" | uint64) :: ("channelUpdate" | channelUpdateCodec)).as[FeeInsufficient])
.typecase(UPDATE | 13, (("expiry" | uint32) :: ("channelUpdate" | channelUpdateCodec)).as[IncorrectCltvExpiry])
.typecase(UPDATE | 14, (("channelUpdate" | channelUpdateCodec)).as[ExpiryTooSoon])
.typecase(UPDATE | 20, (("flags" | binarydata(2)) :: ("channelUpdate" | channelUpdateCodec)).as[ChannelDisabled])
.typecase(UPDATE | 11, (("amountMsat" | uint64) :: ("channelUpdate" | channelUpdateWithLengthCodec)).as[AmountBelowMinimum])
.typecase(UPDATE | 12, (("amountMsat" | uint64) :: ("channelUpdate" | channelUpdateWithLengthCodec)).as[FeeInsufficient])
.typecase(UPDATE | 13, (("expiry" | uint32) :: ("channelUpdate" | channelUpdateWithLengthCodec)).as[IncorrectCltvExpiry])
.typecase(UPDATE | 14, (("channelUpdate" | channelUpdateWithLengthCodec)).as[ExpiryTooSoon])
.typecase(UPDATE | 20, (("flags" | binarydata(2)) :: ("channelUpdate" | channelUpdateWithLengthCodec)).as[ChannelDisabled])
.typecase(PERM | 15, provide(UnknownPaymentHash))
.typecase(PERM | 16, provide(IncorrectPaymentAmount))
.typecase(17, provide(FinalExpiryTooSoon))
.typecase(18, (("expiry" | uint32)).as[FinalIncorrectCltvExpiry])
.typecase(19, (("amountMsat" | uint32)).as[FinalIncorrectHtlcAmount])
.typecase(21, provide(ExpiryTooFar))
}

View File

@ -1,6 +1,6 @@
package fr.acinq.eclair.wire
import fr.acinq.bitcoin.BinaryData
import fr.acinq.bitcoin.{BinaryData, Block}
import org.junit.runner.RunWith
import org.scalatest.FunSuite
import org.scalatest.junit.JUnitRunner
@ -12,6 +12,16 @@ import scala.util.Random
*/
@RunWith(classOf[JUnitRunner])
class FailureMessageLightningMessageCodecsSpec extends FunSuite {
val channelUpdate = ChannelUpdate(
signature = BinaryData("3045022100c451cd65c88f55b1767941a247e849e12f5f4d4a93a07316659e22f5267d2088022009042a595c6bc8942cd9d729317b82b306edc259fb6b3a3cecb3dd1bd446e90601"),
chainHash = Block.RegtestGenesisBlock.hash,
shortChannelId = 12345,
timestamp = 1234567L,
cltvExpiryDelta = 100,
flags = BinaryData("0001"),
htlcMinimumMsat = 1000,
feeBaseMsat = 12,
feeProportionalMillionths = 76)
def randomBytes(size: Int): BinaryData = {
val bin = new Array[Byte](size)
@ -20,14 +30,12 @@ class FailureMessageLightningMessageCodecsSpec extends FunSuite {
}
test("encode/decode all channel messages") {
val invalidRealm = InvalidRealm
val temporaryNodeFailure = TemporaryNodeFailure
val permanentNodeFailure = PermanentNodeFailure
val msgs: List[FailureMessage] =
invalidRealm :: temporaryNodeFailure :: permanentNodeFailure :: Nil
InvalidRealm :: TemporaryNodeFailure :: PermanentNodeFailure :: RequiredNodeFeatureMissing ::
InvalidOnionVersion(randomBytes(32)) :: InvalidOnionHmac(randomBytes(32)) :: InvalidOnionKey(randomBytes(32)) ::
TemporaryChannelFailure(channelUpdate) :: PermanentChannelFailure :: RequiredChannelFeatureMissing :: UnknownNextPeer ::
AmountBelowMinimum(123456, channelUpdate) :: FeeInsufficient(546463, channelUpdate) :: IncorrectCltvExpiry(1211, channelUpdate) :: ExpiryTooSoon(channelUpdate) ::
UnknownPaymentHash :: IncorrectPaymentAmount :: FinalExpiryTooSoon :: FinalIncorrectCltvExpiry(1234) :: ChannelDisabled(BinaryData("0101"), channelUpdate) :: ExpiryTooFar :: Nil
msgs.foreach {
case msg => {
@ -37,5 +45,4 @@ class FailureMessageLightningMessageCodecsSpec extends FunSuite {
}
}
}
}