Skip to content

Commit

Permalink
Correctly set htlc_minimum in blinded paths
Browse files Browse the repository at this point in the history
We must use the most restrictive value for `htlc_minimum`, not the
least restrictive one. When we don't have the remote channel update
we should use the value from our node params.

The `htlc_maximum` is allowed to be twice the payment amount according
to the BOLTs: we reflect that in the blinded path data.
  • Loading branch information
t-bast committed Aug 22, 2024
1 parent e1b162a commit 073efa0
Show file tree
Hide file tree
Showing 2 changed files with 12 additions and 4 deletions.
12 changes: 8 additions & 4 deletions src/commonMain/kotlin/fr/acinq/lightning/payment/OfferManager.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,12 @@ import fr.acinq.bitcoin.ByteVector32
import fr.acinq.bitcoin.PublicKey
import fr.acinq.bitcoin.utils.Either.Left
import fr.acinq.bitcoin.utils.Either.Right
import fr.acinq.lightning.*
import fr.acinq.lightning.EncodedNodeId
import fr.acinq.lightning.Features
import fr.acinq.lightning.Lightning.randomBytes32
import fr.acinq.lightning.Lightning.randomKey
import fr.acinq.lightning.NodeParams
import fr.acinq.lightning.WalletParams
import fr.acinq.lightning.crypto.RouteBlinding
import fr.acinq.lightning.io.OfferInvoiceReceived
import fr.acinq.lightning.io.OfferNotPaid
Expand All @@ -18,7 +21,6 @@ import fr.acinq.lightning.message.OnionMessages.Destination
import fr.acinq.lightning.message.OnionMessages.IntermediateNode
import fr.acinq.lightning.message.OnionMessages.buildMessage
import fr.acinq.lightning.utils.currentTimestampMillis
import fr.acinq.lightning.utils.msat
import fr.acinq.lightning.utils.toByteVector
import fr.acinq.lightning.wire.*
import kotlinx.coroutines.flow.MutableSharedFlow
Expand Down Expand Up @@ -168,8 +170,10 @@ class OfferManager(val nodeParams: NodeParams, val walletParams: WalletParams, v
// This ensures that even when payers haven't received the latest block(s) or don't include a safety margin in the
// expiry they use, we can still safely receive their payment.
cltvExpiryDelta = cltvExpiryDelta + nodeParams.minFinalCltvExpiryDelta,
minHtlc = remoteChannelUpdates.minOfOrNull { it.htlcMinimumMsat } ?: 1.msat,
maxHtlc = amount,
// We must use the most restrictive minimum HTLC value between local and remote.
minHtlc = (listOf(nodeParams.htlcMinimum) + remoteChannelUpdates.map { it.htlcMinimumMsat }).max(),
// Payments are allowed to overpay at most two times the invoice amount.
maxHtlc = amount * 2,
allowedFeatures = Features.empty
)
val remoteNodePayload = RouteBlindingEncryptedData(
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -89,6 +89,8 @@ class OfferManagerTestsCommon : LightningTestSuite() {
val path = payInvoice.invoice.blindedPaths.first()
assertEquals(EncodedNodeId(aliceTrampolineKey.publicKey()), path.route.route.introductionNodeId)
assertEquals(aliceOfferManager.nodeParams.expiryDeltaBlocks + aliceOfferManager.nodeParams.minFinalCltvExpiryDelta, path.paymentInfo.cltvExpiryDelta)
assertEquals(TestConstants.Alice.nodeParams.htlcMinimum, path.paymentInfo.minHtlc)
assertEquals(payOffer.amount * 2, path.paymentInfo.maxHtlc)
}

@Test
Expand Down Expand Up @@ -121,6 +123,8 @@ class OfferManagerTestsCommon : LightningTestSuite() {
val path = payInvoice.invoice.blindedPaths.first()
assertEquals(EncodedNodeId(aliceTrampolineKey.publicKey()), path.route.route.introductionNodeId)
assertEquals(aliceOfferManager.nodeParams.expiryDeltaBlocks + aliceOfferManager.nodeParams.minFinalCltvExpiryDelta, path.paymentInfo.cltvExpiryDelta)
assertEquals(TestConstants.Alice.nodeParams.htlcMinimum, path.paymentInfo.minHtlc)
assertEquals(payOffer.amount * 2, path.paymentInfo.maxHtlc)
}

@Test
Expand Down

0 comments on commit 073efa0

Please sign in to comment.