@@ -42,7 +42,7 @@ import fr.acinq.eclair.router.Router.{ChannelHop, HopRelayParams, Route, RoutePa
4242import fr .acinq .eclair .router .{BalanceTooLow , RouteNotFound }
4343import fr .acinq .eclair .wire .protocol .PaymentOnion .IntermediatePayload
4444import fr .acinq .eclair .wire .protocol ._
45- import fr .acinq .eclair .{Alias , CltvExpiry , CltvExpiryDelta , EncodedNodeId , Features , Logs , MilliSatoshi , MilliSatoshiLong , NodeParams , TimestampMilli , UInt64 , nodeFee , randomBytes32 }
45+ import fr .acinq .eclair .{Alias , CltvExpiry , CltvExpiryDelta , EncodedNodeId , Features , InitFeature , Logs , MilliSatoshi , MilliSatoshiLong , NodeParams , TimestampMilli , UInt64 , nodeFee , randomBytes32 }
4646
4747import java .util .UUID
4848import java .util .concurrent .TimeUnit
@@ -164,8 +164,8 @@ object NodeRelay {
164164 }
165165
166166 /** If we fail to relay a payment, we may want to attempt on-the-fly funding if it makes sense. */
167- private def shouldAttemptOnTheFlyFunding (nodeParams : NodeParams , failures : Seq [PaymentFailure ]): Boolean = {
168- val featureOk = nodeParams.features.hasFeature( Features .OnTheFlyFunding )
167+ private def shouldAttemptOnTheFlyFunding (nodeParams : NodeParams , recipientFeatures_opt : Option [ Features [ InitFeature ]], failures : Seq [PaymentFailure ]): Boolean = {
168+ val featureOk = Features .canUseFeature( nodeParams.features.initFeatures(), recipientFeatures_opt.getOrElse( Features .empty), Features .OnTheFlyFunding )
169169 val balanceTooLow = failures.collectFirst { case f@ LocalFailure (_, _, BalanceTooLow ) => f }.nonEmpty
170170 val routeNotFound = failures.collectFirst { case f@ LocalFailure (_, _, RouteNotFound ) => f }.nonEmpty
171171 featureOk && (balanceTooLow || routeNotFound)
@@ -298,7 +298,7 @@ class NodeRelay private(nodeParams: NodeParams,
298298 private def ensureRecipientReady (upstream : Upstream .Hot .Trampoline , recipient : Recipient , nextPayload : IntermediatePayload .NodeRelay , nextPacket_opt : Option [OnionRoutingPacket ]): Behavior [Command ] = {
299299 nextWalletNodeId(nodeParams, recipient) match {
300300 case Some (walletNodeId) if nodeParams.peerWakeUpConfig.enabled => waitForPeerReady(upstream, walletNodeId, recipient, nextPayload, nextPacket_opt)
301- case _ => relay(upstream, recipient, nextPayload, nextPacket_opt)
301+ case _ => relay(upstream, recipient, None , nextPayload, nextPacket_opt)
302302 }
303303 }
304304
@@ -316,14 +316,14 @@ class NodeRelay private(nodeParams: NodeParams,
316316 context.log.warn(" rejecting payment: failed to wake-up remote peer" )
317317 rejectPayment(upstream, Some (UnknownNextPeer ()))
318318 stopping()
319- case WrappedPeerReadyResult (_ : PeerReadyNotifier .PeerReady ) =>
320- relay(upstream, recipient, nextPayload, nextPacket_opt)
319+ case WrappedPeerReadyResult (r : PeerReadyNotifier .PeerReady ) =>
320+ relay(upstream, recipient, Some (r.remoteFeatures), nextPayload, nextPacket_opt)
321321 }
322322 }
323323 }
324324
325325 /** Relay the payment to the next identified node: this is similar to sending an outgoing payment. */
326- private def relay (upstream : Upstream .Hot .Trampoline , recipient : Recipient , payloadOut : IntermediatePayload .NodeRelay , packetOut_opt : Option [OnionRoutingPacket ]): Behavior [Command ] = {
326+ private def relay (upstream : Upstream .Hot .Trampoline , recipient : Recipient , recipientFeatures_opt : Option [ Features [ InitFeature ]], payloadOut : IntermediatePayload .NodeRelay , packetOut_opt : Option [OnionRoutingPacket ]): Behavior [Command ] = {
327327 context.log.debug(" relaying trampoline payment (amountIn={} expiryIn={} amountOut={} expiryOut={})" , upstream.amountIn, upstream.expiryIn, payloadOut.amountToForward, payloadOut.outgoingCltv)
328328 val confidence = (upstream.received.map(_.add.endorsement).min + 0.5 ) / 8
329329 val paymentCfg = SendPaymentConfig (relayId, relayId, None , paymentHash, recipient.nodeId, upstream, None , None , storeInDb = false , publishEvent = false , recordPathFindingMetrics = true , confidence)
@@ -342,7 +342,7 @@ class NodeRelay private(nodeParams: NodeParams,
342342 }
343343 val payFSM = outgoingPaymentFactory.spawnOutgoingPayFSM(context, paymentCfg, useMultiPart)
344344 payFSM ! payment
345- sending(upstream, recipient, payloadOut, TimestampMilli .now(), fulfilledUpstream = false )
345+ sending(upstream, recipient, recipientFeatures_opt, payloadOut, TimestampMilli .now(), fulfilledUpstream = false )
346346 }
347347
348348 /**
@@ -354,6 +354,7 @@ class NodeRelay private(nodeParams: NodeParams,
354354 */
355355 private def sending (upstream : Upstream .Hot .Trampoline ,
356356 recipient : Recipient ,
357+ recipientFeatures_opt : Option [Features [InitFeature ]],
357358 nextPayload : IntermediatePayload .NodeRelay ,
358359 startedAt : TimestampMilli ,
359360 fulfilledUpstream : Boolean ): Behavior [Command ] =
@@ -365,7 +366,7 @@ class NodeRelay private(nodeParams: NodeParams,
365366 // We want to fulfill upstream as soon as we receive the preimage (even if not all HTLCs have fulfilled downstream).
366367 context.log.debug(" got preimage from downstream" )
367368 fulfillPayment(upstream, paymentPreimage)
368- sending(upstream, recipient, nextPayload, startedAt, fulfilledUpstream = true )
369+ sending(upstream, recipient, recipientFeatures_opt, nextPayload, startedAt, fulfilledUpstream = true )
369370 } else {
370371 // we don't want to fulfill multiple times
371372 Behaviors .same
@@ -381,7 +382,7 @@ class NodeRelay private(nodeParams: NodeParams,
381382 stopping()
382383 case WrappedPaymentFailed (PaymentFailed (_, _, failures, _)) =>
383384 nextWalletNodeId(nodeParams, recipient) match {
384- case Some (walletNodeId) if shouldAttemptOnTheFlyFunding(nodeParams, failures) =>
385+ case Some (walletNodeId) if shouldAttemptOnTheFlyFunding(nodeParams, recipientFeatures_opt, failures) =>
385386 context.log.info(" trampoline payment failed, attempting on-the-fly funding" )
386387 attemptOnTheFlyFunding(upstream, walletNodeId, recipient, nextPayload, failures, startedAt)
387388 case _ =>
0 commit comments