@@ -5,20 +5,99 @@ 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;
20+ use secp256k1:: { Secp256k1 , SecretKey } ;
1821use secp256k1:: key:: PublicKey ;
1922use std:: convert:: TryInto ;
2023use std:: ops:: Deref ;
2124
25+ /// TODO docs after interface is settled
26+ /// TODO instead of passing in the secret, pass in an InvoiceSigner trait object that ChannelManager
27+ /// implements, maybe?
28+ pub fn create_multi_receive_invoice ( amt_msat : Option < u64 > , description : String , payment_hash : PaymentHash , payment_secret : PaymentSecret , channels : & [ ( u64 , PublicKey , & ChannelDetails ) ] , fake_node_secret : SecretKey , network : Currency ) ->
29+ Result < Invoice , SignOrCreationError < ( ) > >
30+ {
31+ let fake_node_pubkey = PublicKey :: from_secret_key ( & Secp256k1 :: new ( ) , & fake_node_secret) ;
32+ let mut route_hints = vec ! [ ] ;
33+ for ( fake_scid, real_node_pubkey, channel) in channels {
34+ let short_channel_id = match channel. short_channel_id {
35+ Some ( id) => id,
36+ None => continue ,
37+ } ;
38+ let forwarding_info = match & channel. counterparty . forwarding_info {
39+ Some ( info) => info. clone ( ) ,
40+ None => continue ,
41+ } ;
42+ route_hints. push ( RouteHint ( vec ! [
43+ RouteHintHop {
44+ src_node_id: channel. counterparty. node_id,
45+ short_channel_id,
46+ fees: RoutingFees {
47+ base_msat: forwarding_info. fee_base_msat,
48+ proportional_millionths: forwarding_info. fee_proportional_millionths,
49+ } ,
50+ cltv_expiry_delta: forwarding_info. cltv_expiry_delta,
51+ htlc_minimum_msat: None ,
52+ htlc_maximum_msat: None ,
53+ } ,
54+ RouteHintHop {
55+ src_node_id: * real_node_pubkey,
56+ short_channel_id: * fake_scid,
57+ fees: RoutingFees {
58+ base_msat: 0 ,
59+ proportional_millionths: 0 ,
60+ } ,
61+ cltv_expiry_delta: MIN_CLTV_EXPIRY_DELTA ,
62+ htlc_minimum_msat: None ,
63+ htlc_maximum_msat: None ,
64+ }
65+ ] )
66+ ) ;
67+ }
68+ // TODO handle empty route hints
69+ // TODO comment why mpp isn't enabled
70+ let mut invoice = InvoiceBuilder :: new ( network)
71+ . description ( description)
72+ . current_timestamp ( )
73+ . payee_pub_key ( fake_node_pubkey)
74+ . payment_hash ( Hash :: from_slice ( & payment_hash. 0 ) . unwrap ( ) )
75+ . payment_secret ( payment_secret)
76+ . min_final_cltv_expiry ( MIN_FINAL_CLTV_EXPIRY . into ( ) ) ;
77+ if let Some ( amt) = amt_msat {
78+ invoice = invoice. amount_milli_satoshis ( amt) ;
79+ }
80+ for hint in route_hints {
81+ invoice = invoice. private_route ( hint) ;
82+ }
83+
84+ let raw_invoice = match invoice. build_raw ( ) {
85+ Ok ( inv) => inv,
86+ Err ( e) => return Err ( SignOrCreationError :: CreationError ( e) )
87+ } ;
88+ let hrp_str = raw_invoice. hrp . to_string ( ) ;
89+ let hrp_bytes = hrp_str. as_bytes ( ) ;
90+ let data_without_signature = raw_invoice. data . to_base32 ( ) ;
91+ let invoice_preimage = RawInvoice :: construct_invoice_preimage ( hrp_bytes, & data_without_signature) ;
92+ let secp_ctx = Secp256k1 :: new ( ) ;
93+ let invoice_preimage_msg = secp256k1:: Message :: from_slice ( & Sha256 :: hash ( & invoice_preimage) ) . unwrap ( ) ;
94+ let signed_raw_invoice = raw_invoice. sign ( |_| Ok ( secp_ctx. sign_recoverable ( & invoice_preimage_msg, & fake_node_secret) ) ) ;
95+ match signed_raw_invoice {
96+ Ok ( inv) => Ok ( Invoice :: from_signed ( inv) . unwrap ( ) ) ,
97+ Err ( e) => Err ( SignOrCreationError :: SignError ( e) )
98+ }
99+ }
100+
22101/// Utility to construct an invoice. Generally, unless you want to do something like a custom
23102/// cltv_expiry, this is what you should be using to create an invoice. The reason being, this
24103/// method stores the invoice's payment secret and preimage in `ChannelManager`, so (a) the user
@@ -155,16 +234,22 @@ where
155234}
156235
157236#[ cfg( test) ]
158- mod test {
237+ mod tests {
159238 use { Currency , Description , InvoiceDescription } ;
160- use lightning:: ln:: PaymentHash ;
161- use lightning:: ln:: channelmanager:: MIN_FINAL_CLTV_EXPIRY ;
239+ use lightning:: { expect_payment_sent, get_revoke_commit_msgs} ;
240+ use lightning:: chain:: keysinterface:: KeyMaterial ;
241+ use lightning:: ln:: { PaymentPreimage , PaymentHash } ;
242+ use lightning:: ln:: channelmanager:: { ChannelDetails , MIN_FINAL_CLTV_EXPIRY } ;
162243 use lightning:: ln:: functional_test_utils:: * ;
163244 use lightning:: ln:: features:: InitFeatures ;
164245 use lightning:: ln:: msgs:: ChannelMessageHandler ;
165246 use lightning:: routing:: router:: { Payee , RouteParameters , find_route} ;
166- use lightning:: util:: events:: MessageSendEventsProvider ;
247+ use lightning:: util:: events:: { Event , MessageSendEvent , MessageSendEventsProvider , PaymentPurpose } ;
167248 use lightning:: util:: test_utils;
249+ use bitcoin_hashes:: sha256:: Hash as Sha256 ;
250+ use bitcoin_hashes:: Hash ;
251+ use secp256k1:: PublicKey ;
252+
168253 #[ test]
169254 fn test_from_channelmanager ( ) {
170255 let chanmon_cfgs = create_chanmon_cfgs ( 2 ) ;
@@ -215,4 +300,128 @@ mod test {
215300 let events = nodes[ 1 ] . node . get_and_clear_pending_msg_events ( ) ;
216301 assert_eq ! ( events. len( ) , 2 ) ;
217302 }
303+
304+ #[ test]
305+ fn test_multi_node_receive ( ) {
306+ do_test_multi_node_receive ( true ) ;
307+ do_test_multi_node_receive ( false ) ;
308+ }
309+
310+ fn do_test_multi_node_receive ( user_generated_pmt_hash : bool ) {
311+ let chanmon_cfgs = create_chanmon_cfgs ( 3 ) ;
312+ let node_cfgs = create_node_cfgs ( 3 , & chanmon_cfgs) ;
313+ let node_chanmgrs = create_node_chanmgrs ( 3 , & node_cfgs, & [ None , None , None ] ) ;
314+ let nodes = create_network ( 3 , & node_cfgs, & node_chanmgrs) ;
315+ let chan_0_1 = create_announced_chan_between_nodes_with_value ( & nodes, 0 , 1 , 100000 , 10001 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
316+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 1 ] . node . get_our_node_id ( ) , & chan_0_1. 1 ) ;
317+ nodes[ 1 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_0_1. 0 ) ;
318+ let chan_0_2 = create_announced_chan_between_nodes_with_value ( & nodes, 0 , 2 , 100000 , 10001 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
319+ nodes[ 0 ] . node . handle_channel_update ( & nodes[ 2 ] . node . get_our_node_id ( ) , & chan_0_2. 1 ) ;
320+ nodes[ 2 ] . node . handle_channel_update ( & nodes[ 0 ] . node . get_our_node_id ( ) , & chan_0_2. 0 ) ;
321+ let phantom_key_material = KeyMaterial ( [ 42 ; 32 ] ) ;
322+ let phantom_scid = 42 ;
323+ let phantom_secret = nodes[ 1 ] . node . create_fake_last_hop ( phantom_key_material, phantom_scid) ;
324+ nodes[ 2 ] . node . create_fake_last_hop ( phantom_key_material, phantom_scid) ;
325+
326+ let ( mut payment_preimage_opt, payment_hash, payment_secret) = {
327+ if user_generated_pmt_hash {
328+ let payment_preimage = PaymentPreimage ( [ 1 ; 32 ] ) ;
329+ let payment_hash = PaymentHash ( Sha256 :: hash ( & payment_preimage. 0 [ ..] ) . into_inner ( ) ) ;
330+ let payment_secret = nodes[ 1 ] . node . create_inbound_payment_for_hash_fake_last_hop ( payment_hash, Some ( 10_000 ) , 3600 , phantom_scid) . unwrap ( ) ;
331+ ( Some ( payment_preimage) , payment_hash, payment_secret)
332+ } else {
333+ let ( payment_hash, payment_secret) = nodes[ 1 ] . node . create_inbound_payment_for_fake_last_hop ( Some ( 10_000 ) , 3600 , phantom_scid) . unwrap ( ) ;
334+ ( None , payment_hash, payment_secret)
335+ }
336+ } ;
337+ let channels_1 = nodes[ 1 ] . node . list_channels ( ) ;
338+ let channels_2 = nodes[ 2 ] . node . list_channels ( ) ;
339+ let mut route_hints = channels_1. iter ( ) . map ( |e| ( phantom_scid, nodes[ 1 ] . node . get_our_node_id ( ) , e) ) . collect :: < Vec < ( u64 , PublicKey , & ChannelDetails ) > > ( ) ;
340+ for channel in channels_2. iter ( ) {
341+ route_hints. push ( ( phantom_scid, nodes[ 2 ] . node . get_our_node_id ( ) , & channel) ) ;
342+ }
343+ let invoice = :: utils:: create_multi_receive_invoice ( Some ( 10_000 ) , "test" . to_string ( ) , payment_hash, payment_secret, & route_hints, phantom_secret, Currency :: BitcoinTestnet ) . unwrap ( ) ;
344+
345+ assert_eq ! ( invoice. min_final_cltv_expiry( ) , MIN_FINAL_CLTV_EXPIRY as u64 ) ;
346+ assert_eq ! ( invoice. description( ) , InvoiceDescription :: Direct ( & Description ( "test" . to_string( ) ) ) ) ;
347+ assert_eq ! ( invoice. route_hints( ) . len( ) , 2 ) ;
348+ // assert!(!invoice.features().unwrap().supports_basic_mpp()); todo get this work?
349+
350+ let payee = Payee :: from_node_id ( invoice. recover_payee_pub_key ( ) )
351+ . with_features ( invoice. features ( ) . unwrap ( ) . clone ( ) )
352+ . with_route_hints ( invoice. route_hints ( ) ) ;
353+ let params = RouteParameters {
354+ payee,
355+ final_value_msat : invoice. amount_milli_satoshis ( ) . unwrap ( ) ,
356+ final_cltv_expiry_delta : invoice. min_final_cltv_expiry ( ) as u32 ,
357+ } ;
358+ let first_hops = nodes[ 0 ] . node . list_usable_channels ( ) ;
359+ let network_graph = node_cfgs[ 0 ] . network_graph ;
360+ let logger = test_utils:: TestLogger :: new ( ) ;
361+ let scorer = test_utils:: TestScorer :: with_fixed_penalty ( 0 ) ;
362+ let route = find_route (
363+ & nodes[ 0 ] . node . get_our_node_id ( ) , & params, network_graph,
364+ Some ( & first_hops. iter ( ) . collect :: < Vec < _ > > ( ) ) , & logger, & scorer,
365+ ) . unwrap ( ) ;
366+ let payment_event = {
367+ let mut payment_hash = PaymentHash ( [ 0 ; 32 ] ) ;
368+ payment_hash. 0 . copy_from_slice ( & invoice. payment_hash ( ) . as_ref ( ) [ 0 ..32 ] ) ;
369+ nodes[ 0 ] . node . send_payment ( & route, payment_hash, & Some ( invoice. payment_secret ( ) . clone ( ) ) ) . unwrap ( ) ;
370+ let mut added_monitors = nodes[ 0 ] . chain_monitor . added_monitors . lock ( ) . unwrap ( ) ;
371+ assert_eq ! ( added_monitors. len( ) , 1 ) ;
372+ added_monitors. clear ( ) ;
373+
374+ let mut events = nodes[ 0 ] . node . get_and_clear_pending_msg_events ( ) ;
375+ assert_eq ! ( events. len( ) , 1 ) ;
376+ SendEvent :: from_event ( events. remove ( 0 ) )
377+ } ;
378+ nodes[ 1 ] . node . handle_update_add_htlc ( & nodes[ 0 ] . node . get_our_node_id ( ) , & payment_event. msgs [ 0 ] ) ;
379+ nodes[ 1 ] . node . handle_commitment_signed ( & nodes[ 0 ] . node . get_our_node_id ( ) , & payment_event. commitment_msg ) ;
380+ check_added_monitors ! ( nodes[ 1 ] , 1 ) ;
381+ let ( raa_1, cs_1) = get_revoke_commit_msgs ! ( nodes[ 1 ] , nodes[ 0 ] . node. get_our_node_id( ) ) ;
382+ check_added_monitors ! ( nodes[ 1 ] , 0 ) ;
383+ assert ! ( nodes[ 1 ] . node. get_and_clear_pending_msg_events( ) . is_empty( ) ) ;
384+ nodes[ 0 ] . node . handle_revoke_and_ack ( & nodes[ 1 ] . node . get_our_node_id ( ) , & raa_1) ;
385+ assert ! ( nodes[ 0 ] . node. get_and_clear_pending_msg_events( ) . is_empty( ) ) ;
386+ check_added_monitors ! ( nodes[ 0 ] , 1 ) ;
387+ nodes[ 0 ] . node . handle_commitment_signed ( & nodes[ 1 ] . node . get_our_node_id ( ) , & cs_1) ;
388+ let raa_0 = {
389+ let events = nodes[ 0 ] . node . get_and_clear_pending_msg_events ( ) ;
390+ assert_eq ! ( events. len( ) , 1 ) ;
391+ match events[ 0 ] {
392+ MessageSendEvent :: SendRevokeAndACK { ref node_id, ref msg } => {
393+ assert_eq ! ( * node_id, nodes[ 1 ] . node. get_our_node_id( ) ) ;
394+ ( * msg) . clone ( )
395+ } ,
396+ _ => panic ! ( "Unexpected event" ) ,
397+ }
398+ } ;
399+ check_added_monitors ! ( nodes[ 0 ] , 1 ) ;
400+ nodes[ 1 ] . node . handle_revoke_and_ack ( & nodes[ 0 ] . node . get_our_node_id ( ) , & raa_0) ;
401+
402+ let events = nodes[ 1 ] . node . get_and_clear_pending_events ( ) ;
403+ assert_eq ! ( events. len( ) , 1 ) ;
404+ match events[ 0 ] {
405+ Event :: PendingHTLCsForwardable { .. } => { } ,
406+ _ => panic ! ( "Unexpected event" ) ,
407+ } ;
408+ nodes[ 1 ] . node . process_pending_htlc_forwards ( ) ;
409+ let events = nodes[ 1 ] . node . get_and_clear_pending_events ( ) ;
410+ assert_eq ! ( events. len( ) , 1 ) ;
411+ match events[ 0 ] {
412+ Event :: PaymentReceived {
413+ purpose : PaymentPurpose :: InvoicePayment { payment_preimage, payment_secret : secret } , ..
414+ } => {
415+ assert_eq ! ( payment_secret, secret) ;
416+ if let Some ( preimage) = payment_preimage {
417+ payment_preimage_opt = Some ( preimage) ;
418+ }
419+ } ,
420+ _ => panic ! ( "Unexpected event" ) ,
421+ }
422+ check_added_monitors ! ( nodes[ 1 ] , 1 ) ;
423+
424+ do_claim_payment_along_route ( & nodes[ 0 ] , & vec ! ( & vec!( & nodes[ 1 ] ) [ ..] ) , false , payment_preimage_opt. unwrap ( ) ) ;
425+ expect_payment_sent ! ( nodes[ 0 ] , payment_preimage_opt. unwrap( ) , Some ( 0 ) ) ;
426+ }
218427}
0 commit comments