mirror of
https://github.com/ACINQ/eclair.git
synced 2024-11-20 10:39:19 +01:00
Check when relay fee is insufficient (#634)
We should return a `FeeInsufficient` error when an incoming htlc doesn't pay us what we require in our latest `channel_update`. Note that the spec encourages us to being a bit more lax than that (BOLT 7): > SHOULD accept HTLCs that pay an older fee, for some reasonable time after sending channel_update. > Note: this allows for any propagation delay.
This commit is contained in:
parent
b7b9f4929a
commit
a9348f0774
@ -18,12 +18,13 @@ package fr.acinq.eclair.payment
|
|||||||
|
|
||||||
import akka.actor.{Actor, ActorLogging, ActorRef, Props, Status}
|
import akka.actor.{Actor, ActorLogging, ActorRef, Props, Status}
|
||||||
import fr.acinq.bitcoin.{BinaryData, Crypto, MilliSatoshi}
|
import fr.acinq.bitcoin.{BinaryData, Crypto, MilliSatoshi}
|
||||||
|
import fr.acinq.eclair.nodeFee
|
||||||
import fr.acinq.eclair.channel._
|
import fr.acinq.eclair.channel._
|
||||||
import fr.acinq.eclair.crypto.Sphinx
|
import fr.acinq.eclair.crypto.Sphinx
|
||||||
import fr.acinq.eclair.payment.PaymentLifecycle.{PaymentFailed, PaymentSucceeded}
|
import fr.acinq.eclair.payment.PaymentLifecycle.{PaymentFailed, PaymentSucceeded}
|
||||||
import fr.acinq.eclair.router.Announcements
|
import fr.acinq.eclair.router.Announcements
|
||||||
import fr.acinq.eclair.wire._
|
import fr.acinq.eclair.wire._
|
||||||
import fr.acinq.eclair.{Globals, NodeParams, ShortChannelId}
|
import fr.acinq.eclair.{NodeParams, ShortChannelId}
|
||||||
import scodec.bits.BitVector
|
import scodec.bits.BitVector
|
||||||
import scodec.{Attempt, DecodeResult}
|
import scodec.{Attempt, DecodeResult}
|
||||||
|
|
||||||
@ -104,6 +105,8 @@ class Relayer(nodeParams: NodeParams, register: ActorRef, paymentHandler: ActorR
|
|||||||
Left(CMD_FAIL_HTLC(add.id, Right(AmountBelowMinimum(add.amountMsat, channelUpdate)), commit = true))
|
Left(CMD_FAIL_HTLC(add.id, Right(AmountBelowMinimum(add.amountMsat, channelUpdate)), commit = true))
|
||||||
case Some(channelUpdate) if add.expiry != perHopPayload.outgoingCltvValue + channelUpdate.cltvExpiryDelta =>
|
case Some(channelUpdate) if add.expiry != perHopPayload.outgoingCltvValue + channelUpdate.cltvExpiryDelta =>
|
||||||
Left(CMD_FAIL_HTLC(add.id, Right(IncorrectCltvExpiry(add.expiry, channelUpdate)), commit = true))
|
Left(CMD_FAIL_HTLC(add.id, Right(IncorrectCltvExpiry(add.expiry, channelUpdate)), commit = true))
|
||||||
|
case Some(channelUpdate) if (add.amountMsat - perHopPayload.amtToForward) < nodeFee(channelUpdate.feeBaseMsat, channelUpdate.feeProportionalMillionths, perHopPayload.amtToForward) =>
|
||||||
|
Left(CMD_FAIL_HTLC(add.id, Right(FeeInsufficient(add.amountMsat, channelUpdate)), commit = true))
|
||||||
case _ =>
|
case _ =>
|
||||||
Right(CMD_ADD_HTLC(perHopPayload.amtToForward, add.paymentHash, perHopPayload.outgoingCltvValue, nextPacket.serialize, upstream_opt = Some(add), commit = true))
|
Right(CMD_ADD_HTLC(perHopPayload.amtToForward, add.paymentHash, perHopPayload.outgoingCltvValue, nextPacket.serialize, upstream_opt = Some(add), commit = true))
|
||||||
}
|
}
|
||||||
|
@ -30,6 +30,7 @@ import fr.acinq.eclair.wire._
|
|||||||
import fr.acinq.eclair.{Globals, TestConstants, TestkitBaseClass}
|
import fr.acinq.eclair.{Globals, TestConstants, TestkitBaseClass}
|
||||||
import org.junit.runner.RunWith
|
import org.junit.runner.RunWith
|
||||||
import org.scalatest.junit.JUnitRunner
|
import org.scalatest.junit.JUnitRunner
|
||||||
|
import scodec.bits.BitVector
|
||||||
|
|
||||||
import scala.concurrent.duration._
|
import scala.concurrent.duration._
|
||||||
|
|
||||||
@ -234,6 +235,25 @@ class RelayerSpec extends TestkitBaseClass {
|
|||||||
paymentHandler.expectNoMsg(100 millis)
|
paymentHandler.expectNoMsg(100 millis)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
test("fail to relay an htlc-add when relay fee isn't sufficient") { case (relayer, register, paymentHandler) =>
|
||||||
|
val sender = TestProbe()
|
||||||
|
|
||||||
|
val hops1 = hops.updated(1, hops(1).copy(lastUpdate = hops(1).lastUpdate.copy(feeBaseMsat = hops(1).lastUpdate.feeBaseMsat / 2)))
|
||||||
|
val (cmd, _) = buildCommand(finalAmountMsat, finalExpiry, paymentHash, hops1)
|
||||||
|
// and then manually build an htlc
|
||||||
|
val add_ab = UpdateAddHtlc(channelId = channelId_ab, id = 123456, cmd.amountMsat, cmd.paymentHash, cmd.expiry, cmd.onion)
|
||||||
|
relayer ! LocalChannelUpdate(null, channelId_bc, channelUpdate_bc.shortChannelId, c, None, channelUpdate_bc)
|
||||||
|
|
||||||
|
sender.send(relayer, ForwardAdd(add_ab))
|
||||||
|
|
||||||
|
val fail = register.expectMsgType[Register.Forward[CMD_FAIL_HTLC]].message
|
||||||
|
assert(fail.id === add_ab.id)
|
||||||
|
assert(fail.reason == Right(FeeInsufficient(add_ab.amountMsat, channelUpdate_bc)))
|
||||||
|
|
||||||
|
register.expectNoMsg(100 millis)
|
||||||
|
paymentHandler.expectNoMsg(100 millis)
|
||||||
|
}
|
||||||
|
|
||||||
test("fail an htlc-add at the final node when amount has been modified by second-to-last node") { case (relayer, register, paymentHandler) =>
|
test("fail an htlc-add at the final node when amount has been modified by second-to-last node") { case (relayer, register, paymentHandler) =>
|
||||||
val sender = TestProbe()
|
val sender = TestProbe()
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user