From 4d9deff0914c869f0f4a2014b95fe5d35dc2bd75 Mon Sep 17 00:00:00 2001 From: Arik Sosman Date: Sun, 9 Feb 2025 22:41:16 -0800 Subject: [PATCH 1/3] Switch RequiredWrapper to LengthReadable In a subsequent commit, we will be storing `TrampolineOnionPacket`s within `PendingHTLCRouting`, requiring that they be serialized for storage. To do so, `RequiredWrapper`'s requirements must be loosened to only require `LengthReadable` instead of `Readable`. --- lightning/src/util/ser.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/lightning/src/util/ser.rs b/lightning/src/util/ser.rs index 083cfa2ad6c..21997c09c1a 100644 --- a/lightning/src/util/ser.rs +++ b/lightning/src/util/ser.rs @@ -403,10 +403,10 @@ impl MaybeReadable for T { /// /// This is not exported to bindings users as manual TLV building is not currently supported in bindings pub struct RequiredWrapper(pub Option); -impl Readable for RequiredWrapper { +impl LengthReadable for RequiredWrapper { #[inline] - fn read(reader: &mut R) -> Result { - Ok(Self(Some(Readable::read(reader)?))) + fn read_from_fixed_length_buffer(reader: &mut R) -> Result { + Ok(Self(Some(LengthReadable::read_from_fixed_length_buffer(reader)?))) } } impl> ReadableArgs for RequiredWrapper { From b616559aae09344711dbc15a1bde07752b3f9a3d Mon Sep 17 00:00:00 2001 From: Arik Sosman Date: Sun, 9 Feb 2025 22:42:25 -0800 Subject: [PATCH 2/3] Add TrampolineForward variant to PendingHTLCRouting Forwarding Trampoline packets requires storing their shared secrets on top of the outer onion's shared secrets, as well as referencing the next hop by its node ID as opposed to by an SCID. We modify PendingHTLCRouting to adequately represent this information. --- Cargo.toml | 1 + lightning/src/ln/channelmanager.rs | 63 ++++++++++++++++++++++++++++++ 2 files changed, 64 insertions(+) diff --git a/Cargo.toml b/Cargo.toml index dc3eb92c7e2..698f5112b9d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -62,6 +62,7 @@ check-cfg = [ "cfg(ldk_bench)", "cfg(ldk_test_vectors)", "cfg(taproot)", + "cfg(trampoline)", "cfg(require_route_graph_test)", "cfg(splicing)", "cfg(async_payments)", diff --git a/lightning/src/ln/channelmanager.rs b/lightning/src/ln/channelmanager.rs index eb5bd89575a..2697c14e6b4 100644 --- a/lightning/src/ln/channelmanager.rs +++ b/lightning/src/ln/channelmanager.rs @@ -55,6 +55,8 @@ use crate::ln::channel_state::ChannelDetails; use crate::types::features::{Bolt12InvoiceFeatures, ChannelFeatures, ChannelTypeFeatures, InitFeatures, NodeFeatures}; #[cfg(any(feature = "_test_utils", test))] use crate::types::features::Bolt11InvoiceFeatures; +#[cfg(trampoline)] +use crate::routing::gossip::NodeId; use crate::routing::router::{BlindedTail, FixedRouter, InFlightHtlcs, Path, Payee, PaymentParameters, Route, RouteParameters, Router}; use crate::ln::onion_payment::{check_incoming_htlc_cltv, create_recv_pending_htlc_info, create_fwd_pending_htlc_info, decode_incoming_update_add_htlc_onion, InboundHTLCErr, NextPacketDetails}; use crate::ln::msgs; @@ -169,6 +171,24 @@ pub enum PendingHTLCRouting { /// The absolute CLTV of the inbound HTLC incoming_cltv_expiry: Option, }, + /// An HTLC which should be forwarded on to another Trampoline node. + #[cfg(trampoline)] + TrampolineForward { + /// The onion shared secret we build with the sender (or the preceding Trampoline node) used + /// to decrypt the onion. + /// + /// This is later used to encrypt failure packets in the event that the HTLC is failed. + incoming_shared_secret: [u8; 32], + /// The onion which should be included in the forwarded HTLC, telling the next hop what to + /// do with the HTLC. + onion_packet: msgs::TrampolineOnionPacket, + /// The node ID of the Trampoline node which we need to route this HTLC to. + node_id: NodeId, + /// Set if this HTLC is being forwarded within a blinded path. + blinded: Option, + /// The absolute CLTV of the inbound HTLC + incoming_cltv_expiry: u32, + }, /// The onion indicates that this is a payment for an invoice (supposedly) generated by us. /// /// Note that at this point, we have not checked that the invoice being paid was actually @@ -270,6 +290,8 @@ impl PendingHTLCRouting { fn blinded_failure(&self) -> Option { match self { Self::Forward { blinded: Some(BlindedForward { failure, .. }), .. } => Some(*failure), + #[cfg(trampoline)] + Self::TrampolineForward { blinded: Some(BlindedForward { failure, .. }), .. } => Some(*failure), Self::Receive { requires_blinded_error: true, .. } => Some(BlindedFailure::FromBlindedNode), Self::ReceiveKeysend { requires_blinded_error: true, .. } => Some(BlindedFailure::FromBlindedNode), _ => None, @@ -279,6 +301,8 @@ impl PendingHTLCRouting { fn incoming_cltv_expiry(&self) -> Option { match self { Self::Forward { incoming_cltv_expiry, .. } => *incoming_cltv_expiry, + #[cfg(trampoline)] + Self::TrampolineForward { incoming_cltv_expiry, .. } => Some(*incoming_cltv_expiry), Self::Receive { incoming_cltv_expiry, .. } => Some(*incoming_cltv_expiry), Self::ReceiveKeysend { incoming_cltv_expiry, .. } => Some(*incoming_cltv_expiry), } @@ -8909,6 +8933,8 @@ This indicates a bug inside LDK. Please report this error at https://github.com/ for (forward_info, prev_htlc_id) in pending_forwards.drain(..) { let scid = match forward_info.routing { PendingHTLCRouting::Forward { short_channel_id, .. } => short_channel_id, + #[cfg(trampoline)] + PendingHTLCRouting::TrampolineForward { .. } => 0, PendingHTLCRouting::Receive { .. } => 0, PendingHTLCRouting::ReceiveKeysend { .. } => 0, }; @@ -12449,6 +12475,7 @@ impl_writeable_tlv_based!(BlindedForward, { (3, next_blinding_override, option), }); +#[cfg(not(trampoline))] impl_writeable_tlv_based_enum!(PendingHTLCRouting, (0, Forward) => { (0, onion_packet, required), @@ -12477,6 +12504,42 @@ impl_writeable_tlv_based_enum!(PendingHTLCRouting, (11, invoice_request, option), }, ); +#[cfg(trampoline)] +impl_writeable_tlv_based_enum!(PendingHTLCRouting, + (0, Forward) => { + (0, onion_packet, required), + (1, blinded, option), + (2, short_channel_id, required), + (3, incoming_cltv_expiry, option), + }, + (1, Receive) => { + (0, payment_data, required), + (1, phantom_shared_secret, option), + (2, incoming_cltv_expiry, required), + (3, payment_metadata, option), + (5, custom_tlvs, optional_vec), + (7, requires_blinded_error, (default_value, false)), + (9, payment_context, option), + }, + (2, ReceiveKeysend) => { + (0, payment_preimage, required), + (1, requires_blinded_error, (default_value, false)), + (2, incoming_cltv_expiry, required), + (3, payment_metadata, option), + (4, payment_data, option), // Added in 0.0.116 + (5, custom_tlvs, optional_vec), + (7, has_recipient_created_payment_secret, (default_value, false)), + (9, payment_context, option), + (11, invoice_request, option), + }, + (3, TrampolineForward) => { + (0, incoming_shared_secret, required), + (2, onion_packet, required), + (4, blinded, option), + (6, node_id, required), + (8, incoming_cltv_expiry, required), + } +); impl_writeable_tlv_based!(PendingHTLCInfo, { (0, routing, required), From 2c685d26e6482bc2e1d630410847036623dd333f Mon Sep 17 00:00:00 2001 From: Arik Sosman Date: Wed, 12 Feb 2025 00:31:46 -0800 Subject: [PATCH 3/3] Test trampoline-cfg in CI --- ci/ci-tests.sh | 2 ++ 1 file changed, 2 insertions(+) diff --git a/ci/ci-tests.sh b/ci/ci-tests.sh index 198e1c4b13b..8e3edfa43a8 100755 --- a/ci/ci-tests.sh +++ b/ci/ci-tests.sh @@ -131,6 +131,8 @@ RUSTFLAGS="--cfg=taproot" cargo test --verbose --color always -p lightning [ "$CI_MINIMIZE_DISK_USAGE" != "" ] && cargo clean RUSTFLAGS="--cfg=splicing" cargo test --verbose --color always -p lightning [ "$CI_MINIMIZE_DISK_USAGE" != "" ] && cargo clean +RUSTFLAGS="--cfg=trampoline" cargo test --verbose --color always -p lightning +[ "$CI_MINIMIZE_DISK_USAGE" != "" ] && cargo clean RUSTFLAGS="--cfg=async_payments" cargo test --verbose --color always -p lightning [ "$CI_MINIMIZE_DISK_USAGE" != "" ] && cargo clean RUSTFLAGS="--cfg=lsps1_service" cargo test --verbose --color always -p lightning-liquidity