Skip to content

Commit 0b8e2b8

Browse files
committed
Carry LSPS2 BOLT12 parameters in payment metadata
Encode LSPS2 BOLT12 invoice parameters in payment metadata so payment handling can recover them when routing provides the payment context. Co-Authored-By: HAL 9000
1 parent 43a7baa commit 0b8e2b8

9 files changed

Lines changed: 624 additions & 90 deletions

File tree

src/builder.rs

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,7 @@ use lightning::util::persist::{
4343
use lightning::util::ser::ReadableArgs;
4444
use lightning::util::sweep::OutputSweeper;
4545
use lightning_dns_resolver::OMDomainResolver;
46+
use lightning_liquidity::lsps2::router::LSPS2BOLT12Router;
4647
use vss_client::headers::VssHeaderProvider;
4748

4849
use crate::chain::ChainSource;
@@ -75,13 +76,14 @@ use crate::lnurl_auth::LnurlAuth;
7576
use crate::logger::{log_error, LdkLogger, LogLevel, LogWriter, Logger};
7677
use crate::message_handler::NodeCustomMessageHandler;
7778
use crate::payment::asynchronous::om_mailbox::OnionMessageMailbox;
79+
use crate::payment::LdkNodeLSPS2Bolt12PaymentMetadataDecoder;
7880
use crate::peer_store::PeerStore;
7981
use crate::runtime::{Runtime, RuntimeSpawner};
8082
use crate::tx_broadcaster::TransactionBroadcaster;
8183
use crate::types::{
8284
AsyncPersister, ChainMonitor, ChannelManager, DynStore, DynStoreRef, DynStoreWrapper,
83-
GossipSync, Graph, HRNResolver, KeysManager, MessageRouter, OnionMessenger, PaymentStore,
84-
PeerManager, PendingPaymentStore,
85+
GossipSync, Graph, HRNResolver, InnerMessageRouter, KeysManager, MessageRouter, OnionMessenger,
86+
PaymentStore, PeerManager, PendingPaymentStore,
8587
};
8688
use crate::wallet::persist::KVStoreWalletPersister;
8789
use crate::wallet::Wallet;
@@ -1778,12 +1780,19 @@ fn build_with_store_internal(
17781780
}
17791781

17801782
let scoring_fee_params = ProbabilisticScoringFeeParameters::default();
1781-
let router = Arc::new(DefaultRouter::new(
1783+
let inner_router = DefaultRouter::new(
17821784
Arc::clone(&network_graph),
17831785
Arc::clone(&logger),
17841786
Arc::clone(&keys_manager),
17851787
Arc::clone(&scorer),
17861788
scoring_fee_params,
1789+
);
1790+
let inner_message_router =
1791+
InnerMessageRouter::new(Arc::clone(&network_graph), Arc::clone(&keys_manager));
1792+
let router = Arc::new(LSPS2BOLT12Router::new_with_payment_metadata_decoder(
1793+
inner_router,
1794+
Arc::clone(&keys_manager),
1795+
LdkNodeLSPS2Bolt12PaymentMetadataDecoder,
17871796
));
17881797

17891798
let mut user_config = default_user_config(&config);
@@ -1807,8 +1816,7 @@ fn build_with_store_internal(
18071816
}
18081817
}
18091818

1810-
let message_router =
1811-
Arc::new(MessageRouter::new(Arc::clone(&network_graph), Arc::clone(&keys_manager)));
1819+
let message_router: Arc<MessageRouter> = Arc::new(inner_message_router);
18121820

18131821
// Initialize the ChannelManager
18141822
let channel_manager = {
@@ -1927,7 +1935,7 @@ fn build_with_store_internal(
19271935
Arc::clone(&keys_manager),
19281936
Arc::clone(&logger),
19291937
Arc::clone(&channel_manager),
1930-
message_router,
1938+
Arc::clone(&message_router),
19311939
Arc::clone(&channel_manager),
19321940
Arc::clone(&channel_manager),
19331941
Arc::clone(&om_resolver),
@@ -1940,7 +1948,7 @@ fn build_with_store_internal(
19401948
Arc::clone(&keys_manager),
19411949
Arc::clone(&logger),
19421950
Arc::clone(&channel_manager),
1943-
message_router,
1951+
Arc::clone(&message_router),
19441952
Arc::clone(&channel_manager),
19451953
Arc::clone(&channel_manager),
19461954
Arc::clone(&om_resolver),
@@ -2168,6 +2176,7 @@ fn build_with_store_internal(
21682176
output_sweeper,
21692177
peer_manager,
21702178
onion_messenger,
2179+
message_router,
21712180
connection_manager,
21722181
keys_manager,
21732182
network_graph,

src/event.rs

Lines changed: 59 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77

88
use core::future::Future;
99
use core::task::{Poll, Waker};
10-
use std::collections::VecDeque;
10+
use std::collections::{BTreeMap, VecDeque};
1111
use std::ops::Deref;
1212
use std::sync::{Arc, Mutex};
1313

@@ -50,7 +50,7 @@ use crate::payment::asynchronous::static_invoice_store::StaticInvoiceStore;
5050
use crate::payment::store::{
5151
PaymentDetails, PaymentDetailsUpdate, PaymentDirection, PaymentKind, PaymentStatus,
5252
};
53-
use crate::payment::PaymentMetadata;
53+
use crate::payment::{PaymentMetadata, LDK_NODE_BOLT12_PAYMENT_METADATA_KEY};
5454
use crate::runtime::Runtime;
5555
use crate::types::{
5656
CustomTlvRecord, DynStore, KeysManager, OnionMessenger, PaymentStore, Sweeper, Wallet,
@@ -600,8 +600,9 @@ where
600600
}
601601
}
602602

603-
fn lsps2_max_total_opening_fee_msat(payment_metadata: &[u8], amount_msat: u64) -> Option<u64> {
604-
let metadata = PaymentMetadata::read(&mut &payment_metadata[..]).ok()?;
603+
fn lsps2_max_total_opening_fee_msat_from_metadata(
604+
metadata: PaymentMetadata, amount_msat: u64,
605+
) -> Option<u64> {
605606
let lsps2_parameters = metadata.lsps2_parameters?;
606607
lsps2_parameters.max_total_opening_fee_msat.or_else(|| {
607608
lsps2_parameters.max_proportional_opening_fee_ppm_msat.and_then(|max_prop_fee| {
@@ -611,6 +612,19 @@ where
611612
})
612613
}
613614

615+
fn lsps2_max_total_opening_fee_msat(payment_metadata: &[u8], amount_msat: u64) -> Option<u64> {
616+
let metadata = PaymentMetadata::read(&mut &payment_metadata[..]).ok()?;
617+
Self::lsps2_max_total_opening_fee_msat_from_metadata(metadata, amount_msat)
618+
}
619+
620+
fn lsps2_max_total_opening_fee_msat_from_bolt12_metadata(
621+
payment_metadata: Option<&BTreeMap<u64, Vec<u8>>>, amount_msat: u64,
622+
) -> Option<u64> {
623+
let encoded_metadata = payment_metadata?.get(&LDK_NODE_BOLT12_PAYMENT_METADATA_KEY)?;
624+
let metadata = PaymentMetadata::read(&mut &encoded_metadata[..]).ok()?;
625+
Self::lsps2_max_total_opening_fee_msat_from_metadata(metadata, amount_msat)
626+
}
627+
614628
pub async fn handle_event(&self, event: LdkEvent) -> Result<(), ReplayEvent> {
615629
match event {
616630
LdkEvent::FundingGenerationReady {
@@ -799,13 +813,19 @@ where
799813
.and_then(|metadata| {
800814
Self::lsps2_max_total_opening_fee_msat(metadata, amount_msat)
801815
}),
816+
PaymentPurpose::Bolt12OfferPayment { payment_context, .. } => {
817+
Self::lsps2_max_total_opening_fee_msat_from_bolt12_metadata(
818+
payment_context.payment_metadata.as_ref(),
819+
amount_msat,
820+
)
821+
},
802822
_ => None,
803823
};
804824

805825
let Some(max_total_opening_fee_msat) = max_total_opening_fee_msat else {
806826
log_info!(
807827
self.logger,
808-
"Refusing inbound payment with hash {} as the counterparty withheld {}msat without valid BOLT11 LSPS2 payment metadata",
828+
"Refusing inbound payment with hash {} as the counterparty withheld {}msat without valid LSPS2 payment metadata",
809829
hex_utils::to_string(&payment_hash.0),
810830
counterparty_skimmed_fee_msat,
811831
);
@@ -829,18 +849,24 @@ where
829849
match &info.kind {
830850
PaymentKind::Bolt11 { .. } => {
831851
let update = PaymentDetailsUpdate {
832-
counterparty_skimmed_fee_msat: Some(Some(counterparty_skimmed_fee_msat)),
852+
counterparty_skimmed_fee_msat: Some(Some(
853+
counterparty_skimmed_fee_msat,
854+
)),
833855
..PaymentDetailsUpdate::new(payment_id)
834856
};
835857
match self.payment_store.update(update).await {
836858
Ok(_) => (),
837859
Err(e) => {
838-
log_error!(self.logger, "Failed to access payment store: {}", e);
860+
log_error!(
861+
self.logger,
862+
"Failed to access payment store: {}",
863+
e
864+
);
839865
return Err(ReplayEvent());
840866
},
841867
};
842868
},
843-
_ => debug_assert!(false, "We only expect the counterparty to get away with withholding fees for BOLT11 payments."),
869+
_ => {},
844870
}
845871
}
846872
}
@@ -1936,6 +1962,7 @@ mod tests {
19361962
max_total_opening_fee_msat: Some(42_000),
19371963
max_proportional_opening_fee_ppm_msat: None,
19381964
}),
1965+
lsps2_bolt12_invoice_parameters: None,
19391966
};
19401967

19411968
assert_eq!(
@@ -1947,14 +1974,37 @@ mod tests {
19471974
);
19481975
}
19491976

1977+
#[test]
1978+
fn lsps2_bolt12_payment_metadata_decodes_total_fee_limit() {
1979+
let metadata = PaymentMetadata {
1980+
lsps2_parameters: Some(LSPS2Parameters {
1981+
max_total_opening_fee_msat: None,
1982+
max_proportional_opening_fee_ppm_msat: Some(10_000),
1983+
}),
1984+
lsps2_bolt12_invoice_parameters: None,
1985+
}
1986+
.encode_as_bolt12_payment_metadata();
1987+
1988+
assert_eq!(
1989+
EventHandler::<Arc<TestLogger>>::lsps2_max_total_opening_fee_msat_from_bolt12_metadata(
1990+
Some(&metadata),
1991+
100_000
1992+
),
1993+
Some(1_000)
1994+
);
1995+
}
1996+
19501997
#[test]
19511998
fn lsps2_payment_metadata_missing_or_malformed_limit_is_rejected() {
1952-
let empty_metadata = PaymentMetadata { lsps2_parameters: None }.encode();
1999+
let empty_metadata =
2000+
PaymentMetadata { lsps2_parameters: None, lsps2_bolt12_invoice_parameters: None }
2001+
.encode();
19532002
let metadata_without_fee_limit = PaymentMetadata {
19542003
lsps2_parameters: Some(LSPS2Parameters {
19552004
max_total_opening_fee_msat: None,
19562005
max_proportional_opening_fee_ppm_msat: None,
19572006
}),
2007+
lsps2_bolt12_invoice_parameters: None,
19582008
}
19592009
.encode();
19602010

src/lib.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,6 @@ use std::time::{Duration, Instant, SystemTime, UNIX_EPOCH};
113113
#[cfg(cycle_tests)]
114114
use std::{any::Any, sync::Weak};
115115

116-
use crate::ffi::maybe_wrap;
117116
pub use balance::{BalanceDetails, LightningBalance, PendingSweepBalance};
118117
pub use bip39;
119118
pub use bitcoin;
@@ -177,12 +176,13 @@ use runtime::Runtime;
177176
pub use tokio;
178177
use types::{
179178
Broadcaster, BumpTransactionEventHandler, ChainMonitor, ChannelManager, DynStore, Graph,
180-
HRNResolver, KeysManager, OnionMessenger, PaymentStore, PeerManager, Router, Scorer, Sweeper,
181-
Wallet,
179+
HRNResolver, KeysManager, MessageRouter, OnionMessenger, PaymentStore, PeerManager, Router,
180+
Scorer, Sweeper, Wallet,
182181
};
183182
pub use types::{ChannelDetails, CustomTlvRecord, PeerDetails, UserChannelId};
184183
pub use vss_client;
185184

185+
use crate::ffi::maybe_wrap;
186186
use crate::scoring::setup_background_pathfinding_scores_sync;
187187
use crate::wallet::FundingAmount;
188188

@@ -229,6 +229,7 @@ pub struct Node {
229229
output_sweeper: Arc<Sweeper>,
230230
peer_manager: Arc<PeerManager>,
231231
onion_messenger: Arc<OnionMessenger>,
232+
message_router: Arc<MessageRouter>,
232233
connection_manager: Arc<ConnectionManager<Arc<Logger>>>,
233234
keys_manager: Arc<KeysManager>,
234235
network_graph: Arc<Graph>,
@@ -928,8 +929,12 @@ impl Node {
928929
Bolt12Payment::new(
929930
Arc::clone(&self.runtime),
930931
Arc::clone(&self.channel_manager),
932+
Arc::clone(&self.message_router),
933+
Arc::clone(&self.connection_manager),
934+
self.liquidity_source.clone(),
931935
Arc::clone(&self.keys_manager),
932936
Arc::clone(&self.payment_store),
937+
Arc::clone(&self.peer_store),
933938
Arc::clone(&self.config),
934939
Arc::clone(&self.is_running),
935940
Arc::clone(&self.logger),
@@ -945,8 +950,12 @@ impl Node {
945950
Arc::new(Bolt12Payment::new(
946951
Arc::clone(&self.runtime),
947952
Arc::clone(&self.channel_manager),
953+
Arc::clone(&self.message_router),
954+
Arc::clone(&self.connection_manager),
955+
self.liquidity_source.clone(),
948956
Arc::clone(&self.keys_manager),
949957
Arc::clone(&self.payment_store),
958+
Arc::clone(&self.peer_store),
950959
Arc::clone(&self.config),
951960
Arc::clone(&self.is_running),
952961
Arc::clone(&self.logger),

0 commit comments

Comments
 (0)