diff --git a/bindings/ldk_node.udl b/bindings/ldk_node.udl index 8ffafff2c..2a0499ce2 100644 --- a/bindings/ldk_node.udl +++ b/bindings/ldk_node.udl @@ -237,8 +237,7 @@ interface PaymentKind { Onchain(); Bolt11(PaymentHash hash, PaymentPreimage? preimage, PaymentSecret? secret, string? bolt11_invoice); Bolt11Jit(PaymentHash hash, PaymentPreimage? preimage, PaymentSecret? secret, LSPFeeLimits lsp_fee_limits); - // TODO: add custom_tlvs here as sequence custom_tlvs - Spontaneous(PaymentHash hash, PaymentPreimage? preimage); + Spontaneous(PaymentHash hash, PaymentPreimage? preimage, sequence custom_tlvs); }; enum PaymentDirection { diff --git a/src/event.rs b/src/event.rs index ac50f5a96..f5f7ac21e 100644 --- a/src/event.rs +++ b/src/event.rs @@ -1,7 +1,7 @@ use crate::types::{DynStore, Sweeper, Wallet}; use crate::{ hex_utils, BumpTransactionEventHandler, ChannelManager, Config, Error, Graph, PeerInfo, - PeerStore, UserChannelId, + PeerStore, TlvEntry, UserChannelId, }; use crate::payment::store::{ @@ -553,17 +553,61 @@ where panic!("Failed to access payment store"); }); } + if let PaymentPurpose::SpontaneousPayment(preimage) = purpose { - // TODO: fix unwrap to have proper error handling and log error - let custom_tlvs = onion_fields.unwrap().custom_tlvs(); + let custom_tlvs = onion_fields + .map(|of| { + of.custom_tlvs() + .iter() + .map(|(t, v)| TlvEntry { r#type: *t, value: v.clone() }) + .collect() + }) + .unwrap_or_default(); log_info!( self.logger, - "Saving spontaneous payment with custom TLVs for payment hash {} of {}msat", - // custom_tlvs, // TODO: log the custom TLVs + "Saving spontaneous payment with custom TLVs {:?} for payment hash {} of {}msat", + custom_tlvs, hex_utils::to_string(&payment_hash.0), amount_msat, ); - // TODO: create payment in pending status and save TLVs as a new field on spontaneous payment in PaymentKind::Spontaneous + + let payment = PaymentDetails { + id: payment_id, + kind: PaymentKind::Spontaneous { + hash: payment_hash, + preimage: Some(preimage), + custom_tlvs, + }, + amount_msat: Some(amount_msat), + direction: PaymentDirection::Inbound, + status: PaymentStatus::Pending, + last_update: time::SystemTime::now() + .duration_since(time::UNIX_EPOCH) + .unwrap_or(time::Duration::ZERO) + .as_secs(), + fee_msat: None, + }; + + match self.payment_store.insert(payment) { + Ok(false) => (), + Ok(true) => { + log_error!( + self.logger, + "Spontaneous payment with hash {} was previously known", + hex_utils::to_string(&payment_hash.0) + ); + debug_assert!(false); + }, + Err(e) => { + log_error!( + self.logger, + "Failed to insert payment with hash {}: {}", + hex_utils::to_string(&payment_hash.0), + e + ); + debug_assert!(false); + }, + }; } }, LdkEvent::PaymentClaimed { @@ -634,30 +678,18 @@ where return; }, PaymentPurpose::SpontaneousPayment(preimage) => { - // TODO: change to updating the payment instead of creating it - // since it now has to be created when checking if the payment is claimable in order to store the custom tlvs - let payment = PaymentDetails { - id: payment_id, - kind: PaymentKind::Spontaneous { - hash: payment_hash, - preimage: Some(preimage), - }, - amount_msat: Some(amount_msat), - direction: PaymentDirection::Inbound, - status: PaymentStatus::Succeeded, - last_update: time::SystemTime::now() - .duration_since(time::UNIX_EPOCH) - .unwrap_or(time::Duration::ZERO) - .as_secs(), - fee_msat: None, + let update = PaymentDetailsUpdate { + preimage: Some(Some(preimage)), + status: Some(PaymentStatus::Succeeded), + ..PaymentDetailsUpdate::new(payment_id) }; - match self.payment_store.insert(payment) { - Ok(false) => (), - Ok(true) => { + match self.payment_store.update(&update) { + Ok(true) => (), + Ok(false) => { log_error!( self.logger, - "Spontaneous payment with hash {} was previously known", + "Payment with hash {} couldn't be found in store", hex_utils::to_string(&payment_hash.0) ); debug_assert!(false); @@ -665,7 +697,7 @@ where Err(e) => { log_error!( self.logger, - "Failed to insert payment with hash {}: {}", + "Failed to update payment with hash {}: {}", hex_utils::to_string(&payment_hash.0), e ); diff --git a/src/payment/spontaneous.rs b/src/payment/spontaneous.rs index c5b954f74..c5ebb56fb 100644 --- a/src/payment/spontaneous.rs +++ b/src/payment/spontaneous.rs @@ -68,7 +68,9 @@ impl SpontaneousPayment { amount_msat, ); let recipient_fields = RecipientOnionFields::spontaneous_empty() - .with_custom_tlvs(custom_tlvs.into_iter().map(|tlv| (tlv.r#type, tlv.value)).collect()) + .with_custom_tlvs( + custom_tlvs.iter().map(|tlv| (tlv.r#type, tlv.value.clone())).collect(), + ) .map_err(|_| { log_error!(self.logger, "Payment error: invalid custom TLVs."); Error::InvalidCustomTlv @@ -89,7 +91,7 @@ impl SpontaneousPayment { kind: PaymentKind::Spontaneous { hash: payment_hash, preimage: Some(payment_preimage), - // TODO: save custom TLVs here from recipient_fields.custom_tlvs() + custom_tlvs, }, status: PaymentStatus::Pending, direction: PaymentDirection::Outbound, @@ -112,6 +114,7 @@ impl SpontaneousPayment { kind: PaymentKind::Spontaneous { hash: payment_hash, preimage: Some(payment_preimage), + custom_tlvs, }, status: PaymentStatus::Failed, diff --git a/src/payment/store.rs b/src/payment/store.rs index 698e8da01..de373490c 100644 --- a/src/payment/store.rs +++ b/src/payment/store.rs @@ -3,7 +3,7 @@ use crate::io::{ PAYMENT_INFO_PERSISTENCE_PRIMARY_NAMESPACE, PAYMENT_INFO_PERSISTENCE_SECONDARY_NAMESPACE, }; use crate::logger::{log_error, Logger}; -use crate::types::DynStore; +use crate::types::{DynStore, TlvEntry}; use crate::Error; use lightning::ln::channelmanager::PaymentId; @@ -108,7 +108,7 @@ impl Readable for PaymentDetails { PaymentKind::Bolt11 { hash, preimage, secret, bolt11_invoice: None } } } else { - PaymentKind::Spontaneous { hash, preimage } + PaymentKind::Spontaneous { hash, preimage, custom_tlvs: Vec::new() } } }; @@ -194,6 +194,8 @@ pub enum PaymentKind { hash: PaymentHash, /// The pre-image used by the payment. preimage: Option, + /// Custom TLVs. + custom_tlvs: Vec, }, } @@ -214,6 +216,7 @@ impl_writeable_tlv_based_enum!(PaymentKind, (8, Spontaneous) => { (0, hash, required), (2, preimage, option), + (131072, custom_tlvs, optional_vec), }; ); diff --git a/src/types.rs b/src/types.rs index 5c2a6983e..ae8b76a43 100644 --- a/src/types.rs +++ b/src/types.rs @@ -2,6 +2,7 @@ use crate::logger::FilesystemLogger; use crate::message_handler::NodeCustomMessageHandler; use lightning::chain::chainmonitor; +use lightning::impl_writeable_tlv_based; use lightning::ln::channelmanager::ChannelDetails as LdkChannelDetails; use lightning::ln::msgs::RoutingMessageHandler; use lightning::ln::msgs::SocketAddress; @@ -478,6 +479,7 @@ impl Default for ChannelConfig { } /// Custom TLV entry. +#[derive(Debug, Clone, PartialEq, Eq)] pub struct TlvEntry { /// Type number. pub r#type: u64, @@ -485,3 +487,8 @@ pub struct TlvEntry { /// Serialized value. pub value: Vec, } + +impl_writeable_tlv_based!(TlvEntry, { + (0, r#type, required), + (1, value, required), +});