1: 6d498bc97 = 1: 6d498bc97 ln: make event optional in EmitEventAndFreeOtherChannel 2: 52c0eb9a5 = 2: 52c0eb9a5 ln/refactor: rename EmitEventAndFreeOtherChannel to note optional event 3: 724750b3b = 3: 724750b3b ln+events: allow multiple prev_channel_id in HTLCHandlingFailed 4: 7c6d93f10 ! 4: 79021ca38 events: add TrampolineForward variant to HTLCHandlingFailureType @@ lightning/src/events/mod.rs: pub enum HTLCHandlingFailureType { + /// We were responsible for pathfinding and forwarding of a trampoline payment, but failed to + /// do so. An example of such an instance is when we can't find a route to the specified + /// trampoline destination. -+ TrampolineForward { -+ /// The set of HTLCs dispatched by our node in an attempt to complete the trampoline forward -+ /// which have failed. -+ attempted_htlcs: Vec, -+ }, ++ TrampolineForward {}, } impl_writeable_tlv_based_enum_upgradable!(HTLCHandlingFailureType, @@ lightning/src/events/mod.rs: impl_writeable_tlv_based_enum_upgradable!(HTLCHandl (4, Receive) => { (0, payment_hash, required), }, -+ (5, TrampolineForward) => { -+ (1, attempted_htlcs, required_vec), -+ }, ++ (5, TrampolineForward) => {}, ); /// The reason for HTLC failures in [`Event::HTLCHandlingFailed`]. 5: 85ed12eb9 = 5: 05b931e08 ln: add TrampolineForward SendHTLCId variant 6: 6b6f3eb31 ! 6: 37eceadbc ln: add TrampolineForward variant to HTLCSource enum @@ Metadata ## Commit message ## ln: add TrampolineForward variant to HTLCSource enum + We only have payment details for HTLCSource::TrampolineForward available + once we've dispatched the payment. If we get to the stage where we need + a HTLCId for the outbound payment, we expect dispatch details to be + present. + Co-authored-by: Arik Sosman Co-authored-by: Maurice Poirrier @@ lightning/src/ln/channelmanager.rs: impl SentHTLCId { prev_outbound_scid_alias: hop_data.prev_outbound_scid_alias, htlc_id: hop_data.htlc_id, }, -+ HTLCSource::TrampolineForward { session_priv, .. } => { -+ Self::TrampolineForward { session_priv: session_priv.secret_bytes() } ++ HTLCSource::TrampolineForward { ++ ref outbound_payment, ++ .. ++ } => Self::TrampolineForward { ++ session_priv: outbound_payment ++ .as_ref() ++ .map(|o| o.session_priv.secret_bytes()) ++ .expect("trying to identify a trampoline payment that we have no outbound_payment tracked for"), + }, HTLCSource::OutboundRoute { session_priv, .. } => { Self::OutboundRoute { session_priv: session_priv.secret_bytes() } }, -@@ lightning/src/ln/channelmanager.rs: mod fuzzy_channelmanager { +@@ lightning/src/ln/channelmanager.rs: type FailedHTLCForward = (HTLCSource, PaymentHash, HTLCFailReason, HTLCHandlingF + mod fuzzy_channelmanager { + use super::*; + ++ /// Information about the outgoing payment dispatched to forward to the next trampoline. ++ #[derive(Clone, Debug, PartialEq, Eq)] ++ pub struct TrampolineDispatch { ++ /// The payment ID used for the outbound payment. ++ pub payment_id: PaymentId, ++ /// The path used for the outbound payment. ++ pub path: Path, ++ /// The session private key used for inter-trampoline outer onions. ++ pub session_priv: SecretKey, ++ } ++ + /// Tracks the inbound corresponding to an outbound HTLC + #[allow(clippy::derive_hash_xor_eq)] // Our Hash is faithful to the data, we just don't have SecretKey::hash #[derive(Clone, Debug, PartialEq, Eq)] pub enum HTLCSource { PreviousHopData(HTLCPreviousHopData), @@ lightning/src/ln/channelmanager.rs: mod fuzzy_channelmanager { + /// need to store the vector of corresponding `HTLCPreviousHopData` values. + previous_hop_data: Vec, + incoming_trampoline_shared_secret: [u8; 32], -+ path: Path, -+ /// In order to decode inter-Trampoline errors, we need to store the session_priv key -+ /// given we're effectively creating new outbound routes. -+ session_priv: SecretKey, ++ /// Track outbound payment details once the payment has been dispatched, will be `None` ++ /// when waiting for incoming MPP to accumulate. ++ outbound_payment: Option, + }, OutboundRoute { path: Path, @@ lightning/src/ln/channelmanager.rs: impl core::hash::Hash for HTLCSource { + HTLCSource::TrampolineForward { + previous_hop_data, + incoming_trampoline_shared_secret, -+ path, -+ session_priv, ++ outbound_payment, + } => { + 2u8.hash(hasher); + previous_hop_data.hash(hasher); + incoming_trampoline_shared_secret.hash(hasher); -+ path.hash(hasher); -+ session_priv[..].hash(hasher); ++ if let Some(payment) = outbound_payment { ++ payment.payment_id.hash(hasher); ++ payment.path.hash(hasher); ++ payment.session_priv[..].hash(hasher); ++ } + }, } } @@ lightning/src/ln/channelmanager.rs: This indicates a bug inside LDK. Please repo } } +@@ lightning/src/ln/channelmanager.rs: impl_writeable_tlv_based!(HTLCPreviousHopData, { + (13, trampoline_shared_secret, option), + }); + ++impl_writeable_tlv_based!(TrampolineDispatch, { ++ (1, payment_id, required), ++ (3, path, required), ++ (5, session_priv, required), ++}); ++ + impl Writeable for ClaimableHTLC { + fn write(&self, writer: &mut W) -> Result<(), io::Error> { + let (payment_data, keysend_preimage) = match &self.onion_payload { @@ lightning/src/ln/channelmanager.rs: impl Readable for HTLCSource { }) } @@ lightning/src/ln/channelmanager.rs: impl Readable for HTLCSource { + _init_and_read_len_prefixed_tlv_fields!(reader, { + (1, previous_hop_data, required_vec), + (3, incoming_trampoline_shared_secret, required), -+ (5, path, required), -+ (7, session_priv, required), ++ (5, outbound_payment, option), + }); + Ok(HTLCSource::TrampolineForward { + previous_hop_data: _init_tlv_based_struct_field!(previous_hop_data, required_vec), + incoming_trampoline_shared_secret: _init_tlv_based_struct_field!(incoming_trampoline_shared_secret, required), -+ path: _init_tlv_based_struct_field!(path, required), -+ session_priv: _init_tlv_based_struct_field!(session_priv, required), ++ outbound_payment, + }) + }, _ => Err(DecodeError::UnknownRequiredFeature), @@ lightning/src/ln/channelmanager.rs: impl Writeable for HTLCSource { + HTLCSource::TrampolineForward { + ref previous_hop_data, + incoming_trampoline_shared_secret, -+ ref session_priv, -+ ref path, ++ ref outbound_payment, + } => { + 2u8.write(writer)?; + write_tlv_fields!(writer, { + (1, *previous_hop_data, required_vec), + (3, incoming_trampoline_shared_secret, required), -+ (5, *path, required), -+ (7, session_priv, required), ++ (5, outbound_payment, option), + }); + }, } -: --------- > 7: bf823d9bb ln: add failure_type helper to HTLCSource for HTLCHandlingFailureType 7: 8fbd1a70d = 8: 35453e582 ln/refactor: add claim funds for htlc forward helper 8: 791ad24c0 = 9: ce3502ff7 ln/refactor: pass closure to create PaymentForwarded event 9: cdf62c610 = 10: d4e4f1543 ln: add trampoline routing payment claiming 10: b13a6d282 = 11: 3349b08a0 ln/refactor: add blinded forwarding failure helper function 11: d4010c758 = 12: 5975cead9 ln: add trampoline routing failure handling 12: 22a527099 = 13: 1ed4b7c68 ln/refactor: extract channelmonitor recovery to external helper 13: ebe16d5a6 = 14: 74a2c4d05 ln: add channel monitor recovery for trampoline forwards 14: 67e4ec338 = 15: 0e63698e4 ln/refactor: move outgoing payment replay code into helper function 15: 13c172a89 = 16: 5cb4c2f61 ln: handle trampoline claims on restart