@@ -50,6 +50,7 @@ use crate::payment::asynchronous::static_invoice_store::StaticInvoiceStore;
5050use crate :: payment:: store:: {
5151 PaymentDetails , PaymentDetailsUpdate , PaymentDirection , PaymentKind , PaymentStatus ,
5252} ;
53+ use crate :: payment:: { EncryptedPaymentMetadata , PaymentMetadata , PaymentMetadataKeys } ;
5354use crate :: runtime:: Runtime ;
5455use crate :: types:: {
5556 CustomTlvRecord , DynStore , KeysManager , OnionMessenger , PaymentStore , Sweeper , Wallet ,
@@ -537,6 +538,7 @@ where
537538 payment_store : Arc < PaymentStore > ,
538539 peer_store : Arc < PeerStore < L > > ,
539540 keys_manager : Arc < KeysManager > ,
541+ payment_metadata_keys : PaymentMetadataKeys ,
540542 runtime : Arc < Runtime > ,
541543 logger : L ,
542544 config : Arc < Config > ,
@@ -556,9 +558,10 @@ where
556558 output_sweeper : Arc < Sweeper > , network_graph : Arc < Graph > ,
557559 liquidity_source : Option < Arc < LiquiditySource < Arc < Logger > > > > ,
558560 payment_store : Arc < PaymentStore > , peer_store : Arc < PeerStore < L > > ,
559- keys_manager : Arc < KeysManager > , static_invoice_store : Option < StaticInvoiceStore > ,
560- onion_messenger : Arc < OnionMessenger > , om_mailbox : Option < Arc < OnionMessageMailbox > > ,
561- runtime : Arc < Runtime > , logger : L , config : Arc < Config > ,
561+ keys_manager : Arc < KeysManager > , payment_metadata_keys : PaymentMetadataKeys ,
562+ static_invoice_store : Option < StaticInvoiceStore > , onion_messenger : Arc < OnionMessenger > ,
563+ om_mailbox : Option < Arc < OnionMessageMailbox > > , runtime : Arc < Runtime > , logger : L ,
564+ config : Arc < Config > ,
562565 ) -> Self {
563566 Self {
564567 event_queue,
@@ -572,6 +575,7 @@ where
572575 payment_store,
573576 peer_store,
574577 keys_manager,
578+ payment_metadata_keys,
575579 logger,
576580 runtime,
577581 config,
@@ -581,6 +585,36 @@ where
581585 }
582586 }
583587
588+ fn fail_claimable_payment (
589+ & self , payment_id : PaymentId , payment_hash : & PaymentHash ,
590+ ) -> Result < ( ) , ReplayEvent > {
591+ self . channel_manager . fail_htlc_backwards ( payment_hash) ;
592+
593+ let update = PaymentDetailsUpdate {
594+ status : Some ( PaymentStatus :: Failed ) ,
595+ ..PaymentDetailsUpdate :: new ( payment_id)
596+ } ;
597+ match self . payment_store . update ( update) {
598+ Ok ( _) => Ok ( ( ) ) ,
599+ Err ( e) => {
600+ log_error ! ( self . logger, "Failed to access payment store: {}" , e) ;
601+ Err ( ReplayEvent ( ) )
602+ } ,
603+ }
604+ }
605+
606+ fn lsps2_max_total_opening_fee_msat (
607+ metadata : & PaymentMetadata , amount_msat : u64 ,
608+ ) -> Option < u64 > {
609+ let lsps2_parameters = metadata. lsps2_parameters ?;
610+ lsps2_parameters. max_total_opening_fee_msat . or_else ( || {
611+ lsps2_parameters. max_proportional_opening_fee_ppm_msat . and_then ( |max_prop_fee| {
612+ // If it's a variable amount payment, compute the actual fee.
613+ compute_opening_fee ( amount_msat, 0 , max_prop_fee)
614+ } )
615+ } )
616+ }
617+
584618 pub async fn handle_event ( & self , event : LdkEvent ) -> Result < ( ) , ReplayEvent > {
585619 match event {
586620 LdkEvent :: FundingGenerationReady {
@@ -694,7 +728,8 @@ where
694728 ..
695729 } => {
696730 let payment_id = PaymentId ( payment_hash. 0 ) ;
697- if let Some ( info) = self . payment_store . get ( & payment_id) {
731+ let payment_info = self . payment_store . get ( & payment_id) ;
732+ if let Some ( info) = payment_info. as_ref ( ) {
698733 if info. direction == PaymentDirection :: Outbound {
699734 log_info ! (
700735 self . logger,
@@ -717,14 +752,13 @@ where
717752 }
718753
719754 if info. status == PaymentStatus :: Succeeded
720- || matches ! ( info. kind, PaymentKind :: Spontaneous { .. } )
755+ || matches ! ( & info. kind, PaymentKind :: Spontaneous { .. } )
721756 {
722- let stored_preimage = match info. kind {
757+ let stored_preimage = match & info. kind {
723758 PaymentKind :: Bolt11 { preimage, .. }
724- | PaymentKind :: Bolt11Jit { preimage, .. }
725759 | PaymentKind :: Bolt12Offer { preimage, .. }
726760 | PaymentKind :: Bolt12Refund { preimage, .. }
727- | PaymentKind :: Spontaneous { preimage, .. } => preimage,
761+ | PaymentKind :: Spontaneous { preimage, .. } => * preimage,
728762 _ => None ,
729763 } ;
730764
@@ -759,22 +793,35 @@ where
759793 } ,
760794 } ;
761795 }
796+ }
762797
763- let max_total_opening_fee_msat = match info. kind {
764- PaymentKind :: Bolt11Jit { lsp_fee_limits, .. } => {
765- lsp_fee_limits
766- . max_total_opening_fee_msat
767- . or_else ( || {
768- lsp_fee_limits. max_proportional_opening_fee_ppm_msat . and_then (
769- |max_prop_fee| {
770- // If it's a variable amount payment, compute the actual fee.
771- compute_opening_fee ( amount_msat, 0 , max_prop_fee)
772- } ,
773- )
774- } )
775- . unwrap_or ( 0 )
776- } ,
777- _ => 0 ,
798+ if counterparty_skimmed_fee_msat > 0 {
799+ let max_total_opening_fee_msat = match & purpose {
800+ PaymentPurpose :: Bolt11InvoicePayment { payment_secret, .. } => onion_fields
801+ . as_ref ( )
802+ . and_then ( |fields| fields. payment_metadata . as_ref ( ) )
803+ . and_then ( |metadata| {
804+ EncryptedPaymentMetadata :: from_raw ( metadata. clone ( ) ) . decrypt (
805+ & self . payment_metadata_keys ,
806+ & payment_hash,
807+ payment_secret,
808+ )
809+ } )
810+ . and_then ( |metadata| {
811+ Self :: lsps2_max_total_opening_fee_msat ( & metadata, amount_msat)
812+ } ) ,
813+ _ => None ,
814+ } ;
815+
816+ let Some ( max_total_opening_fee_msat) = max_total_opening_fee_msat else {
817+ log_info ! (
818+ self . logger,
819+ "Refusing inbound payment with hash {} as the counterparty withheld {}msat without valid BOLT11 LSPS2 payment metadata" ,
820+ hex_utils:: to_string( & payment_hash. 0 ) ,
821+ counterparty_skimmed_fee_msat,
822+ ) ;
823+ self . fail_claimable_payment ( payment_id, & payment_hash) ?;
824+ return Ok ( ( ) ) ;
778825 } ;
779826
780827 if counterparty_skimmed_fee_msat > max_total_opening_fee_msat {
@@ -785,26 +832,13 @@ where
785832 counterparty_skimmed_fee_msat,
786833 max_total_opening_fee_msat,
787834 ) ;
788- self . channel_manager . fail_htlc_backwards ( & payment_hash) ;
789-
790- let update = PaymentDetailsUpdate {
791- hash : Some ( Some ( payment_hash) ) ,
792- status : Some ( PaymentStatus :: Failed ) ,
793- ..PaymentDetailsUpdate :: new ( payment_id)
794- } ;
795- match self . payment_store . update ( update) {
796- Ok ( _) => return Ok ( ( ) ) ,
797- Err ( e) => {
798- log_error ! ( self . logger, "Failed to access payment store: {}" , e) ;
799- return Err ( ReplayEvent ( ) ) ;
800- } ,
801- } ;
835+ self . fail_claimable_payment ( payment_id, & payment_hash) ?;
836+ return Ok ( ( ) ) ;
802837 }
803838
804- // If the LSP skimmed anything, update our stored payment.
805- if counterparty_skimmed_fee_msat > 0 {
806- match info. kind {
807- PaymentKind :: Bolt11Jit { .. } => {
839+ if let Some ( info) = payment_info. as_ref ( ) {
840+ match & info. kind {
841+ PaymentKind :: Bolt11 { .. } => {
808842 let update = PaymentDetailsUpdate {
809843 counterparty_skimmed_fee_msat : Some ( Some ( counterparty_skimmed_fee_msat) ) ,
810844 ..PaymentDetailsUpdate :: new ( payment_id)
@@ -817,16 +851,17 @@ where
817851 } ,
818852 } ;
819853 }
820- _ => debug_assert ! ( false , "We only expect the counterparty to get away with withholding fees for JIT payments." ) ,
854+ _ => debug_assert ! ( false , "We only expect the counterparty to get away with withholding fees for BOLT11 payments." ) ,
821855 }
822856 }
857+ }
823858
859+ if let Some ( info) = payment_info {
824860 // If this is known by the store but ChannelManager doesn't know the preimage,
825861 // the payment has been registered via `_for_hash` variants and needs to be manually claimed via
826862 // user interaction.
827863 match info. kind {
828- PaymentKind :: Bolt11 { preimage, .. }
829- | PaymentKind :: Bolt11Jit { preimage, .. } => {
864+ PaymentKind :: Bolt11 { preimage, .. } => {
830865 if purpose. preimage ( ) . is_none ( ) {
831866 debug_assert ! (
832867 preimage. is_none( ) ,
@@ -1897,8 +1932,50 @@ mod tests {
18971932
18981933 use super :: * ;
18991934 use crate :: io:: test_utils:: InMemoryStore ;
1935+ use crate :: payment:: store:: LSPS2Parameters ;
19001936 use crate :: types:: DynStoreWrapper ;
19011937
1938+ #[ test]
1939+ fn lsps2_payment_metadata_decodes_total_fee_limit ( ) {
1940+ let metadata = PaymentMetadata {
1941+ lsps2_parameters : Some ( LSPS2Parameters {
1942+ max_total_opening_fee_msat : Some ( 42_000 ) ,
1943+ max_proportional_opening_fee_ppm_msat : None ,
1944+ } ) ,
1945+ } ;
1946+
1947+ assert_eq ! (
1948+ EventHandler :: <Arc <TestLogger >>:: lsps2_max_total_opening_fee_msat( & metadata, 100_000 ) ,
1949+ Some ( 42_000 )
1950+ ) ;
1951+ }
1952+
1953+ #[ test]
1954+ fn lsps2_payment_metadata_missing_limit_is_rejected ( ) {
1955+ let empty_metadata = PaymentMetadata { lsps2_parameters : None } ;
1956+ let metadata_without_fee_limit = PaymentMetadata {
1957+ lsps2_parameters : Some ( LSPS2Parameters {
1958+ max_total_opening_fee_msat : None ,
1959+ max_proportional_opening_fee_ppm_msat : None ,
1960+ } ) ,
1961+ } ;
1962+
1963+ assert_eq ! (
1964+ EventHandler :: <Arc <TestLogger >>:: lsps2_max_total_opening_fee_msat(
1965+ & empty_metadata,
1966+ 100_000
1967+ ) ,
1968+ None
1969+ ) ;
1970+ assert_eq ! (
1971+ EventHandler :: <Arc <TestLogger >>:: lsps2_max_total_opening_fee_msat(
1972+ & metadata_without_fee_limit,
1973+ 100_000
1974+ ) ,
1975+ None
1976+ ) ;
1977+ }
1978+
19021979 #[ tokio:: test]
19031980 async fn event_queue_persistence ( ) {
19041981 let store: Arc < DynStore > = Arc :: new ( DynStoreWrapper ( InMemoryStore :: new ( ) ) ) ;
0 commit comments