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 c5a425e3a1..1ac3ee8229 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 @@ -111,6 +111,8 @@ object NodeRelay { Some(TrampolineExpiryTooSoon) } else if (payloadOut.invoiceFeatures.isDefined && payloadOut.paymentSecret.isEmpty) { Some(InvalidOnionPayload(UInt64(8), 0)) // payment secret field is missing + } else if (payloadOut.amountToForward <= MilliSatoshi(0)) { + Some(InvalidOnionPayload(UInt64(2), 0)) } else { None } diff --git a/eclair-core/src/test/scala/fr/acinq/eclair/payment/relay/NodeRelayerSpec.scala b/eclair-core/src/test/scala/fr/acinq/eclair/payment/relay/NodeRelayerSpec.scala index 0bc252af0f..da1d9c1156 100644 --- a/eclair-core/src/test/scala/fr/acinq/eclair/payment/relay/NodeRelayerSpec.scala +++ b/eclair-core/src/test/scala/fr/acinq/eclair/payment/relay/NodeRelayerSpec.scala @@ -353,6 +353,39 @@ class NodeRelayerSpec extends ScalaTestWithActorTestKit(ConfigFactory.load("appl register.expectNoMessage(100 millis) } + test("fail to relay when amount is 0 (single-part)") { f => + import f._ + + val p = createValidIncomingPacket(5000000 msat, 5000000 msat, CltvExpiry(500000), 0 msat, CltvExpiry(490000)) + val (nodeRelayer, _) = f.createNodeRelay(p) + nodeRelayer ! NodeRelay.Relay(p) + + val fwd = register.expectMessageType[Register.Forward[CMD_FAIL_HTLC]] + assert(fwd.channelId === p.add.channelId) + assert(fwd.message === CMD_FAIL_HTLC(p.add.id, Right(InvalidOnionPayload(UInt64(2), 0)), commit = true)) + + register.expectNoMessage(100 millis) + } + + test("fail to relay when amount is 0 (multi-part)") { f => + import f._ + + val p = Seq( + createValidIncomingPacket(4000000 msat, 5000000 msat, CltvExpiry(500000), 0 msat, CltvExpiry(490000)), + createValidIncomingPacket(1000000 msat, 5000000 msat, CltvExpiry(500000), 0 msat, CltvExpiry(490000)) + ) + val (nodeRelayer, _) = f.createNodeRelay(p.head) + p.foreach(p => nodeRelayer ! NodeRelay.Relay(p)) + + p.foreach { p => + val fwd = register.expectMessageType[Register.Forward[CMD_FAIL_HTLC]] + assert(fwd.channelId === p.add.channelId) + assert(fwd.message === CMD_FAIL_HTLC(p.add.id, Right(InvalidOnionPayload(UInt64(2), 0)), commit = true)) + } + + register.expectNoMessage(100 millis) + } + test("fail to relay because outgoing balance isn't sufficient (low fees)") { f => import f._