Skip to content

Commit d33f661

Browse files
committed
WIP
1 parent eaa9e40 commit d33f661

File tree

20 files changed

+144
-77
lines changed

20 files changed

+144
-77
lines changed

TODO.md

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
# TODO
2+
3+
- I removed `enable-trampoline-payments`, so the ACINQ node must:
4+
- activate `trampoline_payment`
5+
- activate `trampoline_payment_prototype` to support previous Phoenix versions
6+
- add trampoline to Bolt 12 features (can be requested in `invoice_request`)
7+
- add blinded relay with trampoline onion (when intermediate node)
8+
- write BOLT spec
9+
- create official test vector for trampoline-to-blinded-path
10+
- add trampoline failures defined in the spec
11+
- `lightning-kmp`:
12+
- must support both options for a while (to allow being paid by older Phoenix)
13+
- Bolt 11 invoices will simply set both feature bits
14+
- Bolt 12 invoices will do it based on what the `invoice_request` contains

docs/TrampolinePayments.md

Lines changed: 1 addition & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,13 +2,7 @@
22

33
Eclair started supporting [trampoline payments](https://github.com/lightning/bolts/pull/829) in v0.3.3.
44

5-
It is disabled by default, as it is still being reviewed for spec acceptance. However, if you want to experiment with it, here is what you can do.
6-
7-
First of all, you need to activate the feature for any node that will act as a trampoline node. Update your `eclair.conf` with the following values:
8-
9-
```conf
10-
eclair.trampoline-payments-enable=true
11-
```
5+
It is now active by default, since it has been added to the [BOLTs](https://github.com/lightning/bolts/pull/836).
126

137
## Sending trampoline payments
148

docs/release-notes/eclair-vnext.md

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ To enable CoinGrinder at all fee rates and prevent the automatic consolidation o
1717
consolidatefeerate=0
1818
```
1919

20+
### Trampoline payments
21+
22+
TODO: link to final spec
23+
2024
### API changes
2125

2226
<insert changes>

eclair-core/src/main/resources/reference.conf

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,6 @@ eclair {
4747
node-alias = "eclair"
4848
node-color = "49daaa"
4949

50-
trampoline-payments-enable = false // TODO: @t-bast: once spec-ed this should use a global feature flag
5150
// see https://github.com/lightningnetwork/lightning-rfc/blob/master/09-features.md
5251
features {
5352
// option_upfront_shutdown_script is not activated by default.
@@ -81,6 +80,7 @@ eclair {
8180
// node that you trust using override-init-features (see below).
8281
option_zeroconf = disabled
8382
keysend = disabled
83+
trampoline_routing = optional
8484
trampoline_payment_prototype = disabled
8585
async_payment_prototype = disabled
8686
}

eclair-core/src/main/scala/fr/acinq/eclair/Features.scala

Lines changed: 11 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -300,13 +300,15 @@ object Features {
300300
val mandatory = 54
301301
}
302302

303-
// TODO: @t-bast: update feature bits once spec-ed (currently reserved here: https://github.com/lightningnetwork/lightning-rfc/issues/605)
304-
// We're not advertising these bits yet in our announcements, clients have to assume support.
305-
// This is why we haven't added them yet to `areSupported`.
306-
// The version of trampoline enabled by this feature bit does not match the latest spec PR: once the spec is accepted,
307-
// we will introduce a new version of trampoline that will work in parallel to this legacy one, until we can safely
308-
// deprecate it.
309-
case object TrampolinePaymentPrototype extends Feature with InitFeature with NodeFeature with Bolt11Feature {
303+
case object TrampolinePayment extends Feature with InitFeature with NodeFeature with Bolt11Feature {
304+
val rfcName = "trampoline_routing"
305+
val mandatory = 56
306+
}
307+
308+
// We don't advertise this feature bit in our announcements (clients assumed support).
309+
// We should keep supporting this version until clients have all migrated to the official version above.
310+
// TODO: remove this and the related onion TLVs once it is unused.
311+
case object TrampolinePaymentPrototype extends Feature with InitFeature with Bolt11Feature {
310312
val rfcName = "trampoline_payment_prototype"
311313
val mandatory = 148
312314
}
@@ -346,6 +348,7 @@ object Features {
346348
PaymentMetadata,
347349
ZeroConf,
348350
KeySend,
351+
TrampolinePayment,
349352
TrampolinePaymentPrototype,
350353
AsyncPaymentPrototype,
351354
SplicePrototype,
@@ -361,6 +364,7 @@ object Features {
361364
RouteBlinding -> (VariableLengthOnion :: Nil),
362365
TrampolinePaymentPrototype -> (PaymentSecret :: Nil),
363366
KeySend -> (VariableLengthOnion :: Nil),
367+
TrampolinePayment -> (BasicMultiPartPayment :: Nil),
364368
AsyncPaymentPrototype -> (TrampolinePaymentPrototype :: Nil)
365369
)
366370

eclair-core/src/main/scala/fr/acinq/eclair/NodeParams.scala

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -81,7 +81,6 @@ case class NodeParams(nodeKeyManager: NodeKeyManager,
8181
socksProxy_opt: Option[Socks5ProxyParams],
8282
maxPaymentAttempts: Int,
8383
paymentFinalExpiry: PaymentFinalExpiryConf,
84-
enableTrampolinePayment: Boolean,
8584
balanceCheckInterval: FiniteDuration,
8685
blockchainWatchdogThreshold: Int,
8786
blockchainWatchdogSources: Seq[String],
@@ -596,7 +595,6 @@ object NodeParams extends Logging {
596595
socksProxy_opt = socksProxy_opt,
597596
maxPaymentAttempts = config.getInt("max-payment-attempts"),
598597
paymentFinalExpiry = PaymentFinalExpiryConf(CltvExpiryDelta(config.getInt("send.recipient-final-expiry.min-delta")), CltvExpiryDelta(config.getInt("send.recipient-final-expiry.max-delta"))),
599-
enableTrampolinePayment = config.getBoolean("trampoline-payments-enable"),
600598
balanceCheckInterval = FiniteDuration(config.getDuration("balance-check-interval").getSeconds, TimeUnit.SECONDS),
601599
blockchainWatchdogThreshold = config.getInt("blockchain-watchdog.missing-blocks-threshold"),
602600
blockchainWatchdogSources = config.getStringList("blockchain-watchdog.sources").asScala.toSeq,

eclair-core/src/main/scala/fr/acinq/eclair/payment/receive/MultiPartHandler.scala

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -329,11 +329,6 @@ object MultiPartHandler {
329329
val paymentHash = Crypto.sha256(paymentPreimage)
330330
val expirySeconds = r.expirySeconds_opt.getOrElse(nodeParams.invoiceExpiry.toSeconds)
331331
val paymentMetadata = hex"2a"
332-
val featuresTrampolineOpt = if (nodeParams.enableTrampolinePayment) {
333-
nodeParams.features.bolt11Features().add(Features.TrampolinePaymentPrototype, FeatureSupport.Optional)
334-
} else {
335-
nodeParams.features.bolt11Features()
336-
}
337332
val invoice = Bolt11Invoice(
338333
nodeParams.chainHash,
339334
r.amount_opt,
@@ -345,7 +340,7 @@ object MultiPartHandler {
345340
expirySeconds = Some(expirySeconds),
346341
extraHops = r.extraHops,
347342
paymentMetadata = Some(paymentMetadata),
348-
features = featuresTrampolineOpt
343+
features = nodeParams.features.bolt11Features()
349344
)
350345
context.log.debug("generated invoice={} from amount={}", invoice.toString, r.amount_opt)
351346
nodeParams.db.payments.addIncomingPayment(invoice, paymentPreimage, r.paymentType)

eclair-core/src/main/scala/fr/acinq/eclair/payment/relay/Relayer.scala

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -29,7 +29,7 @@ import fr.acinq.eclair.channel._
2929
import fr.acinq.eclair.db.PendingCommandsDb
3030
import fr.acinq.eclair.payment._
3131
import fr.acinq.eclair.wire.protocol._
32-
import fr.acinq.eclair.{CltvExpiryDelta, Logs, MilliSatoshi, NodeParams}
32+
import fr.acinq.eclair.{CltvExpiryDelta, Features, Logs, MilliSatoshi, NodeParams}
3333
import grizzled.slf4j.Logging
3434

3535
import scala.concurrent.Promise
@@ -71,7 +71,7 @@ class Relayer(nodeParams: NodeParams, router: ActorRef, register: ActorRef, paym
7171
case Right(r: IncomingPaymentPacket.ChannelRelayPacket) =>
7272
channelRelayer ! ChannelRelayer.Relay(r)
7373
case Right(r: IncomingPaymentPacket.NodeRelayPacket) =>
74-
if (!nodeParams.enableTrampolinePayment) {
74+
if (!nodeParams.features.hasFeature(Features.TrampolinePayment) && !nodeParams.features.hasFeature(Features.TrampolinePaymentPrototype)) {
7575
log.warning(s"rejecting htlc #${add.id} from channelId=${add.channelId} reason=trampoline disabled")
7676
PendingCommandsDb.safeSend(register, nodeParams.db.pendingCommands, add.channelId, CMD_FAIL_HTLC(add.id, Right(RequiredNodeFeatureMissing()), commit = true))
7777
} else {

eclair-core/src/main/scala/fr/acinq/eclair/payment/send/PaymentInitiator.scala

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -84,7 +84,7 @@ class PaymentInitiator(nodeParams: NodeParams, outgoingPaymentFactory: PaymentIn
8484
r.trampolineAttempts match {
8585
case Nil =>
8686
r.replyTo ! PaymentFailed(paymentId, r.paymentHash, LocalFailure(r.recipientAmount, Nil, TrampolineFeesMissing) :: Nil)
87-
case _ if !r.invoice.features.hasFeature(Features.TrampolinePaymentPrototype) && r.invoice.amount_opt.isEmpty =>
87+
case _ if !r.invoice.features.hasFeature(Features.TrampolinePayment) && r.invoice.amount_opt.isEmpty =>
8888
r.replyTo ! PaymentFailed(paymentId, r.paymentHash, LocalFailure(r.recipientAmount, Nil, TrampolineLegacyAmountLessInvoice) :: Nil)
8989
case (trampolineFees, trampolineExpiryDelta) :: remainingAttempts =>
9090
log.info(s"sending trampoline payment with trampoline fees=$trampolineFees and expiry delta=$trampolineExpiryDelta")

eclair-core/src/main/scala/fr/acinq/eclair/payment/send/Recipient.scala

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -241,7 +241,9 @@ case class TrampolineRecipient(invoice: Invoice,
241241
private def createTrampolinePacket(paymentHash: ByteVector32, trampolineHop: NodeHop): Either[OutgoingPaymentError, Sphinx.PacketAndSecrets] = {
242242
invoice match {
243243
case invoice: Bolt11Invoice =>
244-
if (invoice.features.hasFeature(Features.TrampolinePaymentPrototype)) {
244+
if (invoice.features.hasFeature(Features.TrampolinePayment)) {
245+
???
246+
} else if (invoice.features.hasFeature(Features.TrampolinePaymentPrototype)) {
245247
// This is the payload the final recipient will receive, so we use the invoice's payment secret.
246248
val finalPayload = NodePayload(nodeId, FinalPayload.Standard.createPayload(totalAmount, totalAmount, expiry, invoice.paymentSecret, invoice.paymentMetadata, customTlvs))
247249
val trampolinePayload = NodePayload(trampolineHop.nodeId, IntermediatePayload.NodeRelay.Standard(totalAmount, expiry, nodeId))

0 commit comments

Comments
 (0)