@@ -13,6 +13,7 @@ use lightning::ln::{PaymentHash, PaymentPreimage, PaymentSecret};
1313use lightning:: ln:: channelmanager:: { ChannelDetails , ChannelManager , PaymentId , PaymentSendFailure , MIN_FINAL_CLTV_EXPIRY } ;
1414#[ cfg( feature = "std" ) ]
1515use lightning:: ln:: channelmanager:: { PhantomRouteHints , MIN_CLTV_EXPIRY_DELTA } ;
16+ use lightning:: ln:: inbound_payment:: { create, create_from_hash, ExpandedKey } ;
1617use lightning:: ln:: msgs:: LightningError ;
1718use lightning:: routing:: scoring:: Score ;
1819use lightning:: routing:: network_graph:: { NetworkGraph , RoutingFees } ;
@@ -38,29 +39,25 @@ use sync::Mutex;
3839/// may be too long for QR code scanning. To fix this, `PhantomRouteHints::channels` may be pared
3940/// down
4041///
41- /// `payment_hash` and `payment_secret` can come from [`ChannelManager::create_inbound_payment`] or
42+ /// `payment_hash` can come from [`ChannelManager::create_inbound_payment`] or
4243/// [`ChannelManager::create_inbound_payment_for_hash`]. These values can be retrieved from any
43- /// participating node. Alternatively, [`inbound_payment::create`] or
44- /// [`inbound_payment::create_from_hash`] may be used to retrieve these values without a
45- /// `ChannelManager`.
44+ /// participating node. If `None` is provided for `payment_hash`, then one will be created.
4645///
4746/// Note that the provided `keys_manager`'s `KeysInterface` implementation must support phantom
4847/// invoices in its `sign_invoice` implementation ([`PhantomKeysManager`] satisfies this
4948/// requirement).
5049///
5150/// [`PhantomKeysManager`]: lightning::chain::keysinterface::PhantomKeysManager
5251/// [`ChannelManager::get_phantom_route_hints`]: lightning::ln::channelmanager::ChannelManager::get_phantom_route_hints
53- /// [`inbound_payment::create`]: lightning::ln::inbound_payment::create
54- /// [`inbound_payment::create_from_hash`]: lightning::ln::inbound_payment::create_from_hash
5552/// [`PhantomRouteHints::channels`]: lightning::ln::channelmanager::PhantomRouteHints::channels
5653pub fn create_phantom_invoice < Signer : Sign , K : Deref > (
57- amt_msat : Option < u64 > , description : String , payment_hash : PaymentHash , payment_secret : PaymentSecret ,
54+ amt_msat : Option < u64 > , payment_hash : Option < PaymentHash > , description : String , invoice_expiry_delta_secs : u32 ,
5855 phantom_route_hints : Vec < PhantomRouteHints > , keys_manager : K , network : Currency ,
5956) -> Result < Invoice , SignOrCreationError < ( ) > > where K :: Target : KeysInterface {
6057 let description = Description :: new ( description) . map_err ( SignOrCreationError :: CreationError ) ?;
6158 let description = InvoiceDescription :: Direct ( & description, ) ;
6259 _create_phantom_invoice :: < Signer , K > (
63- amt_msat, description , payment_hash , payment_secret , phantom_route_hints, keys_manager, network,
60+ amt_msat, payment_hash , description , invoice_expiry_delta_secs , phantom_route_hints, keys_manager, network,
6461 )
6562}
6663
@@ -80,42 +77,34 @@ pub fn create_phantom_invoice<Signer: Sign, K: Deref>(
8077///
8178/// `description_hash` is a SHA-256 hash of the description text
8279///
83- /// `payment_hash` and `payment_secret` can come from [`ChannelManager::create_inbound_payment`] or
80+ /// `payment_hash` can come from [`ChannelManager::create_inbound_payment`] or
8481/// [`ChannelManager::create_inbound_payment_for_hash`]. These values can be retrieved from any
85- /// participating node. Alternatively, [`inbound_payment::create`] or
86- /// [`inbound_payment::create_from_hash`] may be used to retrieve these values without a
87- /// `ChannelManager`.
82+ /// participating node. If `None` is provided for `payment_hash`, then one will be created.
8883///
8984/// Note that the provided `keys_manager`'s `KeysInterface` implementation must support phantom
9085/// invoices in its `sign_invoice` implementation ([`PhantomKeysManager`] satisfies this
9186/// requirement).
9287///
9388/// [`PhantomKeysManager`]: lightning::chain::keysinterface::PhantomKeysManager
9489/// [`ChannelManager::get_phantom_route_hints`]: lightning::ln::channelmanager::ChannelManager::get_phantom_route_hints
95- /// [`inbound_payment::create`]: lightning::ln::inbound_payment::create
96- /// [`inbound_payment::create_from_hash`]: lightning::ln::inbound_payment::create_from_hash
9790/// [`PhantomRouteHints::channels`]: lightning::ln::channelmanager::PhantomRouteHints::channels
9891pub fn create_phantom_invoice_with_description_hash < Signer : Sign , K : Deref > (
99- amt_msat : Option < u64 > , description_hash : Sha256 , payment_hash : PaymentHash ,
100- payment_secret : PaymentSecret , phantom_route_hints : Vec < PhantomRouteHints > ,
101- keys_manager : K , network : Currency ,
92+ amt_msat : Option < u64 > , payment_hash : Option < PaymentHash > , invoice_expiry_delta_secs : u32 , description_hash : Sha256 , phantom_route_hints : Vec < PhantomRouteHints > , keys_manager : K , network : Currency ,
10293) -> Result < Invoice , SignOrCreationError < ( ) > > where K :: Target : KeysInterface
10394{
104-
10595 _create_phantom_invoice :: < Signer , K > (
106- amt_msat,
107- InvoiceDescription :: Hash ( & description_hash) ,
108- payment_hash, payment_secret, phantom_route_hints, keys_manager, network,
96+ amt_msat, payment_hash, InvoiceDescription :: Hash ( & description_hash) , invoice_expiry_delta_secs, phantom_route_hints, keys_manager, network,
10997 )
11098}
11199
112100#[ cfg( feature = "std" ) ]
113101fn _create_phantom_invoice < Signer : Sign , K : Deref > (
114- amt_msat : Option < u64 > , description : InvoiceDescription , payment_hash : PaymentHash ,
115- payment_secret : PaymentSecret , phantom_route_hints : Vec < PhantomRouteHints > ,
116- keys_manager : K , network : Currency ,
102+ amt_msat : Option < u64 > , payment_hash : Option < PaymentHash > , description : InvoiceDescription , invoice_expiry_delta_secs : u32 ,
103+ phantom_route_hints : Vec < PhantomRouteHints > , keys_manager : K , network : Currency ,
117104) -> Result < Invoice , SignOrCreationError < ( ) > > where K :: Target : KeysInterface
118105{
106+ use std:: time:: { SystemTime , UNIX_EPOCH } ;
107+
119108 if phantom_route_hints. len ( ) == 0 {
120109 return Err ( SignOrCreationError :: CreationError (
121110 CreationError :: MissingRouteHints ,
@@ -128,6 +117,34 @@ fn _create_phantom_invoice<Signer: Sign, K: Deref>(
128117 InvoiceDescription :: Hash ( hash) => InvoiceBuilder :: new ( network) . description_hash ( hash. 0 ) ,
129118 } ;
130119
120+ let keys = ExpandedKey :: new ( & keys_manager. get_inbound_payment_key_material ( ) ) ;
121+ let ( payment_hash, payment_secret) = if let Some ( payment_hash) = payment_hash {
122+ let payment_secret = create_from_hash (
123+ & keys,
124+ amt_msat,
125+ payment_hash,
126+ invoice_expiry_delta_secs,
127+ SystemTime :: now ( )
128+ . duration_since ( UNIX_EPOCH )
129+ . expect ( "Time must be > 1970" )
130+ . as_secs ( ) ,
131+ )
132+ . map_err ( |_| SignOrCreationError :: CreationError ( CreationError :: InvalidAmount ) ) ?;
133+ ( payment_hash, payment_secret)
134+ } else {
135+ create (
136+ & keys,
137+ amt_msat,
138+ invoice_expiry_delta_secs,
139+ & keys_manager,
140+ SystemTime :: now ( )
141+ . duration_since ( UNIX_EPOCH )
142+ . expect ( "Time must be > 1970" )
143+ . as_secs ( ) ,
144+ )
145+ . map_err ( |_| SignOrCreationError :: CreationError ( CreationError :: InvalidAmount ) ) ?
146+ } ;
147+
131148 let mut invoice = invoice
132149 . current_timestamp ( )
133150 . payment_hash ( Hash :: from_slice ( & payment_hash. 0 ) . unwrap ( ) )
@@ -755,23 +772,25 @@ mod test {
755772 nodes[ 2 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_0_2. 0 ) ;
756773
757774 let payment_amt = 10_000 ;
758- let ( payment_preimage, payment_hash, payment_secret) = {
759- if user_generated_pmt_hash {
760- let payment_preimage = PaymentPreimage ( [ 1 ; 32 ] ) ;
761- let payment_hash = PaymentHash ( Sha256 :: hash ( & payment_preimage. 0 [ ..] ) . into_inner ( ) ) ;
762- let payment_secret = nodes[ 1 ] . node . create_inbound_payment_for_hash ( payment_hash, Some ( payment_amt) , 3600 ) . unwrap ( ) ;
763- ( payment_preimage, payment_hash, payment_secret)
764- } else {
765- let ( payment_hash, payment_secret) = nodes[ 1 ] . node . create_inbound_payment ( Some ( payment_amt) , 3600 ) . unwrap ( ) ;
766- let payment_preimage = nodes[ 1 ] . node . get_payment_preimage ( payment_hash, payment_secret) . unwrap ( ) ;
767- ( payment_preimage, payment_hash, payment_secret)
768- }
769- } ;
770775 let route_hints = vec ! [
771776 nodes[ 1 ] . node. get_phantom_route_hints( ) ,
772777 nodes[ 2 ] . node. get_phantom_route_hints( ) ,
773778 ] ;
774- let invoice = :: utils:: create_phantom_invoice :: < EnforcingSigner , & test_utils:: TestKeysInterface > ( Some ( payment_amt) , "test" . to_string ( ) , payment_hash, payment_secret, route_hints, & nodes[ 1 ] . keys_manager , Currency :: BitcoinTestnet ) . unwrap ( ) ;
779+
780+ let user_payment_preimage = PaymentPreimage ( [ 1 ; 32 ] ) ;
781+ let payment_hash = if user_generated_pmt_hash {
782+ Some ( PaymentHash ( Sha256 :: hash ( & user_payment_preimage. 0 [ ..] ) . into_inner ( ) ) )
783+ } else {
784+ None
785+ } ;
786+
787+ let invoice = :: utils:: create_phantom_invoice :: < EnforcingSigner , & test_utils:: TestKeysInterface > ( Some ( payment_amt) , payment_hash, "test" . to_string ( ) , 3600 , route_hints, & nodes[ 1 ] . keys_manager , Currency :: BitcoinTestnet ) . unwrap ( ) ;
788+ let ( payment_hash, payment_secret) = ( PaymentHash ( invoice. payment_hash ( ) . into_inner ( ) ) , * invoice. payment_secret ( ) ) ;
789+ let payment_preimage = if user_generated_pmt_hash {
790+ user_payment_preimage
791+ } else {
792+ nodes[ 1 ] . node . get_payment_preimage ( payment_hash, payment_secret) . unwrap ( )
793+ } ;
775794
776795 assert_eq ! ( invoice. min_final_cltv_expiry( ) , MIN_FINAL_CLTV_EXPIRY as u64 ) ;
777796 assert_eq ! ( invoice. description( ) , InvoiceDescription :: Direct ( & Description ( "test" . to_string( ) ) ) ) ;
@@ -821,6 +840,7 @@ mod test {
821840 // Note that we have to "forward pending HTLCs" twice before we see the PaymentReceived as
822841 // this "emulates" the payment taking two hops, providing some privacy to make phantom node
823842 // payments "look real" by taking more time.
843+
824844 expect_pending_htlcs_forwardable_ignore ! ( nodes[ fwd_idx] ) ;
825845 nodes[ fwd_idx] . node . process_pending_htlc_forwards ( ) ;
826846 expect_pending_htlcs_forwardable_ignore ! ( nodes[ fwd_idx] ) ;
@@ -856,14 +876,13 @@ mod test {
856876 let nodes = create_network ( 3 , & node_cfgs, & node_chanmgrs) ;
857877
858878 let payment_amt = 20_000 ;
859- let ( payment_hash, payment_secret) = nodes[ 1 ] . node . create_inbound_payment ( Some ( payment_amt) , 3600 ) . unwrap ( ) ;
860879 let route_hints = vec ! [
861880 nodes[ 1 ] . node. get_phantom_route_hints( ) ,
862881 nodes[ 2 ] . node. get_phantom_route_hints( ) ,
863882 ] ;
864883
865884 let description_hash = crate :: Sha256 ( Hash :: hash ( "Description hash phantom invoice" . as_bytes ( ) ) ) ;
866- let invoice = :: utils:: create_phantom_invoice_with_description_hash :: < EnforcingSigner , & test_utils:: TestKeysInterface > ( Some ( payment_amt) , description_hash , payment_hash , payment_secret , route_hints, & nodes[ 1 ] . keys_manager , Currency :: BitcoinTestnet ) . unwrap ( ) ;
885+ let invoice = :: utils:: create_phantom_invoice_with_description_hash :: < EnforcingSigner , & test_utils:: TestKeysInterface > ( Some ( payment_amt) , None , 3600 , description_hash , route_hints, & nodes[ 1 ] . keys_manager , Currency :: BitcoinTestnet ) . unwrap ( ) ;
867886
868887 assert_eq ! ( invoice. amount_pico_btc( ) , Some ( 200_000 ) ) ;
869888 assert_eq ! ( invoice. min_final_cltv_expiry( ) , MIN_FINAL_CLTV_EXPIRY as u64 ) ;
@@ -1166,15 +1185,14 @@ mod test {
11661185 mut chan_ids_to_match : HashSet < u64 > ,
11671186 nodes_contains_public_channels : bool
11681187 ) {
1169- let ( payment_hash, payment_secret) = invoice_node. node . create_inbound_payment ( invoice_amt, 3600 ) . unwrap ( ) ;
11701188 let phantom_route_hints = network_multi_nodes. iter ( )
11711189 . map ( |node| node. node . get_phantom_route_hints ( ) )
11721190 . collect :: < Vec < PhantomRouteHints > > ( ) ;
11731191 let phantom_scids = phantom_route_hints. iter ( )
11741192 . map ( |route_hint| route_hint. phantom_scid )
11751193 . collect :: < HashSet < u64 > > ( ) ;
11761194
1177- let invoice = :: utils:: create_phantom_invoice :: < EnforcingSigner , & test_utils:: TestKeysInterface > ( invoice_amt, "test" . to_string ( ) , payment_hash , payment_secret , phantom_route_hints, & invoice_node. keys_manager , Currency :: BitcoinTestnet ) . unwrap ( ) ;
1195+ let invoice = :: utils:: create_phantom_invoice :: < EnforcingSigner , & test_utils:: TestKeysInterface > ( invoice_amt, None , "test" . to_string ( ) , 3600 , phantom_route_hints, & invoice_node. keys_manager , Currency :: BitcoinTestnet ) . unwrap ( ) ;
11781196
11791197 let invoice_hints = invoice. private_routes ( ) ;
11801198
0 commit comments