@@ -5,20 +5,101 @@ use payment::{Payer, Router};
55
66use bech32:: ToBase32 ;
77use bitcoin_hashes:: Hash ;
8+ use bitcoin_hashes:: sha256:: Hash as Sha256 ;
89use lightning:: chain;
910use lightning:: chain:: chaininterface:: { BroadcasterInterface , FeeEstimator } ;
1011use lightning:: chain:: keysinterface:: { Sign , KeysInterface } ;
1112use lightning:: ln:: { PaymentHash , PaymentPreimage , PaymentSecret } ;
12- use lightning:: ln:: channelmanager:: { ChannelDetails , ChannelManager , PaymentId , PaymentSendFailure , MIN_FINAL_CLTV_EXPIRY } ;
13+ use lightning:: ln:: channelmanager:: { ChannelDetails , ChannelManager , PaymentId , PaymentSendFailure , MIN_FINAL_CLTV_EXPIRY , MIN_CLTV_EXPIRY_DELTA } ;
1314use lightning:: ln:: msgs:: LightningError ;
1415use lightning:: routing:: scoring:: Score ;
1516use lightning:: routing:: network_graph:: { NetworkGraph , RoutingFees } ;
1617use lightning:: routing:: router:: { Route , RouteHint , RouteHintHop , RouteParameters , find_route} ;
1718use lightning:: util:: logger:: Logger ;
19+ use secp256k1:: Secp256k1 ;
1820use secp256k1:: key:: PublicKey ;
1921use std:: convert:: TryInto ;
2022use std:: ops:: Deref ;
2123
24+ /// XXX
25+ pub fn create_multi_receive_invoice < Signer : Sign , K : Deref > (
26+ amt_msat : Option < u64 > , description : String , payment_hash : PaymentHash , payment_secret :
27+ PaymentSecret , channels : & [ ( u64 , PublicKey , & ChannelDetails ) ] , keys_manager : K , network : Currency
28+ ) -> Result < Invoice , SignOrCreationError < ( ) > > where K :: Target : KeysInterface {
29+ if channels. len ( ) == 0 {
30+ return Err ( SignOrCreationError :: CreationError ( CreationError :: MissingRouteHints ) )
31+ }
32+ let phantom_secret = match keys_manager. get_phantom_secret ( channels[ 0 ] . 0 ) {
33+ Ok ( s) => s,
34+ Err ( ( ) ) => return Err ( SignOrCreationError :: CreationError ( CreationError :: InvalidPhantomScid ) )
35+ } ;
36+ let mut route_hints = vec ! [ ] ;
37+ for ( fake_scid, real_node_pubkey, channel) in channels {
38+ let short_channel_id = match channel. short_channel_id {
39+ Some ( id) => id,
40+ None => continue ,
41+ } ;
42+ let forwarding_info = match & channel. counterparty . forwarding_info {
43+ Some ( info) => info. clone ( ) ,
44+ None => continue ,
45+ } ;
46+ route_hints. push ( RouteHint ( vec ! [
47+ RouteHintHop {
48+ src_node_id: channel. counterparty. node_id,
49+ short_channel_id,
50+ fees: RoutingFees {
51+ base_msat: forwarding_info. fee_base_msat,
52+ proportional_millionths: forwarding_info. fee_proportional_millionths,
53+ } ,
54+ cltv_expiry_delta: forwarding_info. cltv_expiry_delta,
55+ htlc_minimum_msat: None ,
56+ htlc_maximum_msat: None ,
57+ } ,
58+ RouteHintHop {
59+ src_node_id: * real_node_pubkey,
60+ short_channel_id: * fake_scid,
61+ fees: RoutingFees {
62+ base_msat: 0 ,
63+ proportional_millionths: 0 ,
64+ } ,
65+ cltv_expiry_delta: MIN_CLTV_EXPIRY_DELTA ,
66+ htlc_minimum_msat: None ,
67+ htlc_maximum_msat: None ,
68+ } ] )
69+ ) ;
70+ }
71+ let fake_node_pubkey = PublicKey :: from_secret_key ( & Secp256k1 :: new ( ) , & phantom_secret) ;
72+ let mut invoice = InvoiceBuilder :: new ( network)
73+ . description ( description)
74+ . current_timestamp ( )
75+ . payee_pub_key ( fake_node_pubkey)
76+ . payment_hash ( Hash :: from_slice ( & payment_hash. 0 ) . unwrap ( ) )
77+ . payment_secret ( payment_secret)
78+ . min_final_cltv_expiry ( MIN_FINAL_CLTV_EXPIRY . into ( ) ) ;
79+ if let Some ( amt) = amt_msat {
80+ invoice = invoice. amount_milli_satoshis ( amt) ;
81+ }
82+ for hint in route_hints {
83+ invoice = invoice. private_route ( hint) ;
84+ }
85+
86+ let raw_invoice = match invoice. build_raw ( ) {
87+ Ok ( inv) => inv,
88+ Err ( e) => return Err ( SignOrCreationError :: CreationError ( e) )
89+ } ;
90+ let hrp_str = raw_invoice. hrp . to_string ( ) ;
91+ let hrp_bytes = hrp_str. as_bytes ( ) ;
92+ let data_without_signature = raw_invoice. data . to_base32 ( ) ;
93+ let invoice_preimage = RawInvoice :: construct_invoice_preimage ( hrp_bytes, & data_without_signature) ;
94+ let secp_ctx = Secp256k1 :: new ( ) ;
95+ let invoice_preimage_msg = secp256k1:: Message :: from_slice ( & Sha256 :: hash ( & invoice_preimage) ) . unwrap ( ) ;
96+ let signed_raw_invoice = raw_invoice. sign ( |_| Ok ( secp_ctx. sign_recoverable ( & invoice_preimage_msg, & phantom_secret) ) ) ;
97+ match signed_raw_invoice {
98+ Ok ( inv) => Ok ( Invoice :: from_signed ( inv) . unwrap ( ) ) ,
99+ Err ( e) => Err ( SignOrCreationError :: SignError ( e) )
100+ }
101+ }
102+
22103/// Utility to construct an invoice. Generally, unless you want to do something like a custom
23104/// cltv_expiry, this is what you should be using to create an invoice. The reason being, this
24105/// method stores the invoice's payment secret and preimage in `ChannelManager`, so (a) the user
@@ -160,16 +241,22 @@ where
160241}
161242
162243#[ cfg( test) ]
163- mod test {
244+ mod tests {
164245 use { Currency , Description , InvoiceDescription } ;
165- use lightning:: ln:: PaymentHash ;
166- use lightning:: ln:: channelmanager:: MIN_FINAL_CLTV_EXPIRY ;
246+ use bitcoin_hashes:: Hash ;
247+ use bitcoin_hashes:: sha256:: Hash as Sha256 ;
248+ use lightning:: chain:: keysinterface:: { KeysInterface , KeysManager } ;
249+ use lightning:: ln:: { PaymentPreimage , PaymentHash } ;
250+ use lightning:: ln:: channelmanager:: { ChannelDetails , MIN_FINAL_CLTV_EXPIRY } ;
167251 use lightning:: ln:: functional_test_utils:: * ;
168252 use lightning:: ln:: features:: InitFeatures ;
169253 use lightning:: ln:: msgs:: ChannelMessageHandler ;
170254 use lightning:: routing:: router:: { Payee , RouteParameters , find_route} ;
171- use lightning:: util:: events:: MessageSendEventsProvider ;
255+ use lightning:: util:: enforcing_trait_impls:: EnforcingSigner ;
256+ use lightning:: util:: events:: { MessageSendEvent , MessageSendEventsProvider , Event } ;
172257 use lightning:: util:: test_utils;
258+ use secp256k1:: PublicKey ;
259+
173260 #[ test]
174261 fn test_from_channelmanager ( ) {
175262 let chanmon_cfgs = create_chanmon_cfgs ( 2 ) ;
@@ -220,4 +307,102 @@ mod test {
220307 let events = nodes[ 1 ] . node . get_and_clear_pending_msg_events ( ) ;
221308 assert_eq ! ( events. len( ) , 2 ) ;
222309 }
310+
311+ #[ test]
312+ fn test_multi_node_receive ( ) {
313+ do_test_multi_node_receive ( true ) ;
314+ do_test_multi_node_receive ( false ) ;
315+ }
316+
317+ fn do_test_multi_node_receive ( user_generated_pmt_hash : bool ) {
318+ let mut chanmon_cfgs = create_chanmon_cfgs ( 3 ) ;
319+ let seed = [ 42 as u8 ; 32 ] ;
320+ chanmon_cfgs[ 2 ] . keys_manager . backing = KeysManager :: new_multi_receive ( & seed, 43 , 44 , chanmon_cfgs[ 1 ] . keys_manager . get_inbound_payment_key_material ( ) ) ;
321+ let node_cfgs = create_node_cfgs ( 3 , & chanmon_cfgs) ;
322+ let node_chanmgrs = create_node_chanmgrs ( 3 , & node_cfgs, & [ None , None , None ] ) ;
323+ let nodes = create_network ( 3 , & node_cfgs, & node_chanmgrs) ;
324+ let chan_0_1 = create_announced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 100000 , 10001 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
325+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 1 ] . node . get_our_node_id ( ) , & chan_0_1. 1 ) ;
326+ nodes[ 1 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_0_1. 0 ) ;
327+ let chan_0_2 = create_announced_chan_between_nodes_with_value ( & nodes, 0 , 2 , 100000 , 10001 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
328+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 2 ] . node . get_our_node_id ( ) , & chan_0_2. 1 ) ;
329+ nodes[ 2 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_0_2. 0 ) ;
330+
331+ let payment_amt = 10_000 ;
332+ let ( payment_preimage, payment_hash, payment_secret) = {
333+ if user_generated_pmt_hash {
334+ let payment_preimage = PaymentPreimage ( [ 1 ; 32 ] ) ;
335+ let payment_hash = PaymentHash ( Sha256 :: hash ( & payment_preimage. 0 [ ..] ) . into_inner ( ) ) ;
336+ let payment_secret = nodes[ 1 ] . node . create_inbound_payment_for_hash ( payment_hash, Some ( payment_amt) , 3600 ) . unwrap ( ) ;
337+ ( payment_preimage, payment_hash, payment_secret)
338+ } else {
339+ let ( payment_hash, payment_secret) = nodes[ 1 ] . node . create_inbound_payment ( Some ( payment_amt) , 3600 ) . unwrap ( ) ;
340+ let payment_preimage = nodes[ 1 ] . node . get_payment_preimage ( payment_hash, payment_secret) . unwrap ( ) ;
341+ ( payment_preimage, payment_hash, payment_secret)
342+ }
343+ } ;
344+ let channels_1 = nodes[ 1 ] . node . list_channels ( ) ;
345+ let channels_2 = nodes[ 2 ] . node . list_channels ( ) ;
346+ let mut route_hints = channels_1. iter ( ) . map ( |e| ( nodes[ 1 ] . node . get_phantom_scid ( ) , nodes[ 1 ] . node . get_our_node_id ( ) , e) ) . collect :: < Vec < ( u64 , PublicKey , & ChannelDetails ) > > ( ) ;
347+ for channel in channels_2. iter ( ) {
348+ route_hints. push ( ( nodes[ 2 ] . node . get_phantom_scid ( ) , nodes[ 2 ] . node . get_our_node_id ( ) , & channel) ) ;
349+ }
350+ let invoice = :: utils:: create_multi_receive_invoice :: < EnforcingSigner , & test_utils:: TestKeysInterface > ( Some ( payment_amt) , "test" . to_string ( ) , payment_hash, payment_secret, & route_hints, & nodes[ 1 ] . keys_manager , Currency :: BitcoinTestnet ) . unwrap ( ) ;
351+
352+ assert_eq ! ( invoice. min_final_cltv_expiry( ) , MIN_FINAL_CLTV_EXPIRY as u64 ) ;
353+ assert_eq ! ( invoice. description( ) , InvoiceDescription :: Direct ( & Description ( "test" . to_string( ) ) ) ) ;
354+ assert_eq ! ( invoice. route_hints( ) . len( ) , 2 ) ;
355+ assert ! ( !invoice. features( ) . unwrap( ) . supports_basic_mpp( ) ) ;
356+
357+ let payee = Payee :: from_node_id ( invoice. recover_payee_pub_key ( ) )
358+ . with_features ( invoice. features ( ) . unwrap ( ) . clone ( ) )
359+ . with_route_hints ( invoice. route_hints ( ) ) ;
360+ let params = RouteParameters {
361+ payee,
362+ final_value_msat : invoice. amount_milli_satoshis ( ) . unwrap ( ) ,
363+ final_cltv_expiry_delta : invoice. min_final_cltv_expiry ( ) as u32 ,
364+ } ;
365+ let first_hops = nodes[ 0 ] . node . list_usable_channels ( ) ;
366+ let network_graph = node_cfgs[ 0 ] . network_graph ;
367+ let logger = test_utils:: TestLogger :: new ( ) ;
368+ let scorer = test_utils:: TestScorer :: with_fixed_penalty ( 0 ) ;
369+ let route = find_route (
370+ & nodes[ 0 ] . node . get_our_node_id ( ) , & params, network_graph,
371+ Some ( & first_hops. iter ( ) . collect :: < Vec < _ > > ( ) ) , & logger, & scorer,
372+ ) . unwrap ( ) ;
373+ let payment_event = {
374+ let mut payment_hash = PaymentHash ( [ 0 ; 32 ] ) ;
375+ payment_hash. 0 . copy_from_slice ( & invoice. payment_hash ( ) . as_ref ( ) [ 0 ..32 ] ) ;
376+ nodes[ 0 ] . node . send_payment ( & route, payment_hash, & Some ( invoice. payment_secret ( ) . clone ( ) ) ) . unwrap ( ) ;
377+ let mut added_monitors = nodes[ 0 ] . chain_monitor . added_monitors . lock ( ) . unwrap ( ) ;
378+ assert_eq ! ( added_monitors. len( ) , 1 ) ;
379+ added_monitors. clear ( ) ;
380+
381+ let mut events = nodes[ 0 ] . node . get_and_clear_pending_msg_events ( ) ;
382+ assert_eq ! ( events. len( ) , 1 ) ;
383+ SendEvent :: from_event ( events. remove ( 0 ) )
384+ } ;
385+ nodes[ 1 ] . node . handle_update_add_htlc ( & nodes[ 0 ] . node . get_our_node_id ( ) , & payment_event. msgs [ 0 ] ) ;
386+ commitment_signed_dance ! ( nodes[ 1 ] , nodes[ 0 ] , & payment_event. commitment_msg, false , true ) ;
387+ expect_pending_htlcs_forwardable ! ( nodes[ 1 ] ) ;
388+ let payment_preimage_opt = if user_generated_pmt_hash { None } else { Some ( payment_preimage) } ;
389+ expect_payment_received ! ( nodes[ 1 ] , payment_hash, payment_secret, payment_amt, payment_preimage_opt) ;
390+ do_claim_payment_along_route ( & nodes[ 0 ] , & vec ! ( & vec!( & nodes[ 1 ] ) [ ..] ) , false , payment_preimage) ;
391+ let events = nodes[ 0 ] . node . get_and_clear_pending_events ( ) ;
392+ assert_eq ! ( events. len( ) , 2 ) ;
393+ match events[ 0 ] {
394+ Event :: PaymentSent { payment_preimage : ref ev_preimage, payment_hash : ref ev_hash, ref fee_paid_msat, .. } => {
395+ assert_eq ! ( payment_preimage, * ev_preimage) ;
396+ assert_eq ! ( payment_hash, * ev_hash) ;
397+ assert_eq ! ( fee_paid_msat, & Some ( 0 ) ) ;
398+ } ,
399+ _ => panic ! ( "Unexpected event" )
400+ }
401+ match events[ 1 ] {
402+ Event :: PaymentPathSuccessful { payment_hash : hash, .. } => {
403+ assert_eq ! ( hash, Some ( payment_hash) ) ;
404+ } ,
405+ _ => panic ! ( "Unexpected event" )
406+ }
407+ }
223408}
0 commit comments