@@ -16,7 +16,7 @@ use bitcoin::hashes::sha256::Hash as Sha256;
1616use crate :: blinded_path:: { BlindedHop , BlindedPath } ;
1717use crate :: ln:: PaymentHash ;
1818use crate :: ln:: channelmanager:: { ChannelDetails , PaymentId } ;
19- use crate :: ln:: features:: { ChannelFeatures , InvoiceFeatures , NodeFeatures } ;
19+ use crate :: ln:: features:: { Bolt12InvoiceFeatures , ChannelFeatures , InvoiceFeatures , NodeFeatures } ;
2020use crate :: ln:: msgs:: { DecodeError , ErrorAction , LightningError , MAX_VALUE_MSAT } ;
2121use crate :: offers:: invoice:: BlindedPayInfo ;
2222use crate :: routing:: gossip:: { DirectedChannelInfo , EffectiveCapacity , ReadOnlyNetworkGraph , NetworkGraph , NodeId , RoutingFees } ;
@@ -537,12 +537,12 @@ impl Writeable for PaymentParameters {
537537 let mut blinded_hints = & vec ! [ ] ;
538538 match & self . payee {
539539 Payee :: Clear { route_hints, .. } => clear_hints = route_hints,
540- Payee :: Blinded { route_hints } => blinded_hints = route_hints,
540+ Payee :: Blinded { route_hints, .. } => blinded_hints = route_hints,
541541 }
542542 write_tlv_fields ! ( writer, {
543543 ( 0 , self . payee. node_id( ) , option) ,
544544 ( 1 , self . max_total_cltv_expiry_delta, required) ,
545- ( 2 , if let Payee :: Clear { features , .. } = & self . payee { features } else { & None } , option) ,
545+ ( 2 , self . payee. features( ) , option) ,
546546 ( 3 , self . max_path_count, required) ,
547547 ( 4 , * clear_hints, vec_type) ,
548548 ( 5 , self . max_channel_saturation_power_of_half, required) ,
@@ -560,7 +560,7 @@ impl ReadableArgs<u32> for PaymentParameters {
560560 _init_and_read_tlv_fields ! ( reader, {
561561 ( 0 , payee_pubkey, option) ,
562562 ( 1 , max_total_cltv_expiry_delta, ( default_value, DEFAULT_MAX_TOTAL_CLTV_EXPIRY_DELTA ) ) ,
563- ( 2 , features, option) ,
563+ ( 2 , features, ( option: ReadableArgs , payee_pubkey . is_some ( ) ) ) ,
564564 ( 3 , max_path_count, ( default_value, DEFAULT_MAX_PATH_COUNT ) ) ,
565565 ( 4 , route_hints, vec_type) ,
566566 ( 5 , max_channel_saturation_power_of_half, ( default_value, 2 ) ) ,
@@ -573,12 +573,15 @@ impl ReadableArgs<u32> for PaymentParameters {
573573 let blinded_route_hints = blinded_route_hints. unwrap_or ( vec ! [ ] ) ;
574574 let payee = if blinded_route_hints. len ( ) != 0 {
575575 if clear_route_hints. len ( ) != 0 || payee_pubkey. is_some ( ) { return Err ( DecodeError :: InvalidValue ) }
576- Payee :: Blinded { route_hints : blinded_route_hints }
576+ Payee :: Blinded {
577+ route_hints : blinded_route_hints,
578+ features : features. and_then ( |f : Features | f. bolt12 ( ) ) ,
579+ }
577580 } else {
578581 Payee :: Clear {
579582 route_hints : clear_route_hints,
580583 node_id : payee_pubkey. ok_or ( DecodeError :: InvalidValue ) ?,
581- features,
584+ features : features . and_then ( |f| f . bolt11 ( ) ) ,
582585 }
583586 } ;
584587 Ok ( Self {
@@ -682,6 +685,11 @@ pub enum Payee {
682685 /// Aggregated routing info and blinded paths, for routing to the payee without knowing their
683686 /// node id.
684687 route_hints : Vec < ( BlindedPayInfo , BlindedPath ) > ,
688+ /// Features supported by the payee.
689+ ///
690+ /// May be set from the payee's invoice. May be `None` if the invoice does not contain any
691+ /// features.
692+ features : Option < Bolt12InvoiceFeatures > ,
685693 } ,
686694 /// The recipient included these route hints in their BOLT11 invoice.
687695 Clear {
@@ -709,17 +717,63 @@ impl Payee {
709717 fn node_features ( & self ) -> Option < NodeFeatures > {
710718 match self {
711719 Self :: Clear { features, .. } => features. as_ref ( ) . map ( |f| f. to_context ( ) ) ,
712- _ => None ,
720+ Self :: Blinded { features , .. } => features . as_ref ( ) . map ( |f| f . to_context ( ) ) ,
713721 }
714722 }
715723 fn supports_basic_mpp ( & self ) -> bool {
716724 match self {
717725 Self :: Clear { features, .. } => features. as_ref ( ) . map_or ( false , |f| f. supports_basic_mpp ( ) ) ,
718- _ => false ,
726+ Self :: Blinded { features, .. } => features. as_ref ( ) . map_or ( false , |f| f. supports_basic_mpp ( ) ) ,
727+ }
728+ }
729+ fn features ( & self ) -> Option < FeaturesRef > {
730+ match self {
731+ Self :: Clear { features, .. } => features. as_ref ( ) . map ( |f| FeaturesRef :: Bolt11 ( f) ) ,
732+ Self :: Blinded { features, .. } => features. as_ref ( ) . map ( |f| FeaturesRef :: Bolt12 ( f) ) ,
719733 }
720734 }
721735}
722736
737+ enum FeaturesRef < ' a > {
738+ Bolt11 ( & ' a InvoiceFeatures ) ,
739+ Bolt12 ( & ' a Bolt12InvoiceFeatures ) ,
740+ }
741+ enum Features {
742+ Bolt11 ( InvoiceFeatures ) ,
743+ Bolt12 ( Bolt12InvoiceFeatures ) ,
744+ }
745+
746+ impl Features {
747+ fn bolt12 ( self ) -> Option < Bolt12InvoiceFeatures > {
748+ match self {
749+ Self :: Bolt12 ( f) => Some ( f) ,
750+ _ => None ,
751+ }
752+ }
753+ fn bolt11 ( self ) -> Option < InvoiceFeatures > {
754+ match self {
755+ Self :: Bolt11 ( f) => Some ( f) ,
756+ _ => None ,
757+ }
758+ }
759+ }
760+
761+ impl < ' a > Writeable for FeaturesRef < ' a > {
762+ fn write < W : Writer > ( & self , w : & mut W ) -> Result < ( ) , io:: Error > {
763+ match self {
764+ Self :: Bolt11 ( f) => Ok ( f. write ( w) ?) ,
765+ Self :: Bolt12 ( f) => Ok ( f. write ( w) ?) ,
766+ }
767+ }
768+ }
769+
770+ impl ReadableArgs < bool > for Features {
771+ fn read < R : io:: Read > ( reader : & mut R , bolt11 : bool ) -> Result < Self , DecodeError > {
772+ if bolt11 { return Ok ( Self :: Bolt11 ( Readable :: read ( reader) ?) ) }
773+ Ok ( Self :: Bolt12 ( Readable :: read ( reader) ?) )
774+ }
775+ }
776+
723777/// A list of hops along a payment path terminating with a channel to the recipient.
724778#[ derive( Clone , Debug , Hash , Eq , PartialEq ) ]
725779pub struct RouteHint ( pub Vec < RouteHintHop > ) ;
0 commit comments