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

Reject payments for expired invoices (#1057)

* Reject payments for expired invoices
This commit is contained in:
araspitzu 2019-07-03 15:52:03 +02:00 committed by GitHub
parent 32145e8d6a
commit 20ea9d0e1d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 33 additions and 1 deletions

View File

@ -39,6 +39,7 @@ trait PaymentsDb {
def getPaymentRequest(paymentHash: ByteVector32): Option[PaymentRequest]
// returns non paid payment request
def getPendingPaymentRequestAndPreimage(paymentHash: ByteVector32): Option[(ByteVector32, PaymentRequest)]
def listPaymentRequests(from: Long, to: Long): Seq[PaymentRequest]

View File

@ -65,6 +65,8 @@ class LocalPaymentHandler(nodeParams: NodeParams) extends Actor with ActorLoggin
// it must not be greater than two times the requested amount.
// see https://github.com/lightningnetwork/lightning-rfc/blob/master/04-onion-routing.md#failure-messages
paymentRequest.amount match {
case _ if paymentRequest.isExpired =>
sender ! CMD_FAIL_HTLC(htlc.id, Right(IncorrectOrUnknownPaymentDetails(htlc.amountMsat)), commit = true)
case _ if htlc.cltvExpiry < minFinalExpiry =>
sender ! CMD_FAIL_HTLC(htlc.id, Right(FinalExpiryTooSoon), commit = true)
case Some(amount) if MilliSatoshi(htlc.amountMsat) < amount =>

View File

@ -23,7 +23,8 @@ import fr.acinq.eclair.payment.PaymentRequest._
import scodec.Codec
import scodec.bits.{BitVector, ByteOrdering, ByteVector}
import scodec.codecs.{list, ubyte}
import scala.concurrent.duration._
import scala.compat.Platform
import scala.util.Try
/**
@ -76,6 +77,11 @@ case class PaymentRequest(prefix: String, amount: Option[MilliSatoshi], timestam
case cltvExpiry: PaymentRequest.MinFinalCltvExpiry => cltvExpiry.toLong
}
def isExpired: Boolean = expiry match {
case Some(expiryTime) => timestamp + expiryTime <= Platform.currentTime.milliseconds.toSeconds
case None => timestamp + DEFAULT_EXPIRY_SECONDS <= Platform.currentTime.milliseconds.toSeconds
}
/**
*
* @return the hash of this payment request
@ -104,6 +110,8 @@ case class PaymentRequest(prefix: String, amount: Option[MilliSatoshi], timestam
object PaymentRequest {
val DEFAULT_EXPIRY_SECONDS = 3600
val prefixes = Map(
Block.RegtestGenesisBlock.hash -> "lnbcrt",
Block.TestnetGenesisBlock.hash -> "lntb",

View File

@ -52,6 +52,7 @@ class PaymentHandlerSpec extends TestKit(ActorSystem("test")) with FunSuiteLike
val pr = sender.expectMsgType[PaymentRequest]
assert(nodeParams.db.payments.getIncomingPayment(pr.paymentHash).isEmpty)
assert(nodeParams.db.payments.getPendingPaymentRequestAndPreimage(pr.paymentHash).isDefined)
assert(!nodeParams.db.payments.getPendingPaymentRequestAndPreimage(pr.paymentHash).get._2.isExpired)
val add = UpdateAddHtlc(ByteVector32(ByteVector.fill(32)(1)), 0, amountMsat.amount, pr.paymentHash, expiry, ByteVector.empty)
sender.send(handler, add)
@ -149,4 +150,24 @@ class PaymentHandlerSpec extends TestKit(ActorSystem("test")) with FunSuiteLike
sender.send(handler, ReceivePayment(Some(MilliSatoshi(42000)), "1 coffee without routing info"))
assert(sender.expectMsgType[PaymentRequest].routingInfo === Nil)
}
test("LocalPaymentHandler should reject incoming payments if the payment request is expired") {
val nodeParams = Alice.nodeParams
val handler = TestActorRef[LocalPaymentHandler](LocalPaymentHandler.props(nodeParams))
val sender = TestProbe()
val eventListener = TestProbe()
system.eventStream.subscribe(eventListener.ref, classOf[PaymentReceived])
val amountMsat = MilliSatoshi(42000)
val expiry = Globals.blockCount.get() + 12
sender.send(handler, ReceivePayment(Some(amountMsat), "some desc", expirySeconds_opt = Some(0)))
val pr = sender.expectMsgType[PaymentRequest]
val add = UpdateAddHtlc(ByteVector32(ByteVector.fill(32)(1)), 0, amountMsat.amount, pr.paymentHash, expiry, ByteVector.empty)
sender.send(handler, add)
sender.expectMsgType[CMD_FAIL_HTLC]
assert(nodeParams.db.payments.getIncomingPayment(pr.paymentHash).isEmpty)
}
}