@@ -24,21 +24,19 @@ extern crate secp256k1;
2424use bech32:: u5;
2525use bitcoin_hashes:: Hash ;
2626use bitcoin_hashes:: sha256;
27- use lightning:: ln:: features:: InvoiceFeatures ;
2827use lightning:: ln:: channelmanager:: PaymentSecret ;
29- #[ cfg( any( doc, test) ) ]
30- use lightning:: routing:: network_graph:: RoutingFees ;
28+ use lightning:: ln:: features:: InvoiceFeatures ;
3129use lightning:: routing:: router:: RouteHintHop ;
3230
3331use secp256k1:: key:: PublicKey ;
3432use secp256k1:: { Message , Secp256k1 } ;
3533use secp256k1:: recovery:: RecoverableSignature ;
36- use std:: ops:: Deref ;
3734
35+ use std:: fmt:: { Display , Formatter , self } ;
3836use std:: iter:: FilterMap ;
37+ use std:: ops:: Deref ;
3938use std:: slice:: Iter ;
4039use std:: time:: { SystemTime , Duration , UNIX_EPOCH } ;
41- use std:: fmt:: { Display , Formatter , self } ;
4240
4341mod de;
4442mod ser;
@@ -1292,10 +1290,104 @@ impl<S> Display for SignOrCreationError<S> {
12921290 }
12931291}
12941292
1293+ /// Convenient utilities to create an invoice.
1294+ pub mod utils {
1295+ use { SemanticError , Currency , Invoice , InvoiceBuilder } ;
1296+ use bitcoin_hashes:: Hash ;
1297+ use lightning:: chain;
1298+ use lightning:: chain:: chaininterface:: { BroadcasterInterface , FeeEstimator } ;
1299+ use lightning:: chain:: keysinterface:: { Sign , KeysInterface } ;
1300+ use lightning:: ln:: channelmanager:: { ChannelManager , MIN_FINAL_CLTV_EXPIRY } ;
1301+ use lightning:: ln:: features:: InvoiceFeatures ;
1302+ use lightning:: routing:: network_graph:: RoutingFees ;
1303+ use lightning:: routing:: router:: RouteHintHop ;
1304+ use lightning:: util:: logger:: Logger ;
1305+ use secp256k1:: Secp256k1 ;
1306+ use std:: ops:: Deref ;
1307+
1308+ /// Utility to construct an invoice. Generally, unless you want to do something like a custom
1309+ /// cltv_expiry, this is what you should be using to create an invoice. The reason being, this
1310+ /// method stores the invoice's payment secret and preimage in `ChannelManager`, so (a) the user
1311+ /// doesn't have to store preimage/payment secret information and (b) `ChannelManager` can verify
1312+ /// that the payment secret is valid when the invoice is paid.
1313+ pub fn create_invoice_from_channelmanager < Signer : Sign , M : Deref , T : Deref , K : Deref , F : Deref , L : Deref > (
1314+ channelmanager : & ChannelManager < Signer , M , T , K , F , L > , amt_msat : Option < u64 > , description : String ,
1315+ network : Currency ,
1316+ ) -> Result < Invoice , SemanticError >
1317+ where
1318+ M :: Target : chain:: Watch < Signer > ,
1319+ T :: Target : BroadcasterInterface ,
1320+ K :: Target : KeysInterface < Signer = Signer > ,
1321+ F :: Target : FeeEstimator ,
1322+ L :: Target : Logger ,
1323+ {
1324+ // Marshall route hints.
1325+ let our_channels = channelmanager. list_usable_channels ( ) ;
1326+ let mut route_hints = vec ! [ ] ;
1327+ for channel in our_channels {
1328+ let short_channel_id = match channel. short_channel_id {
1329+ Some ( id) => id,
1330+ None => continue ,
1331+ } ;
1332+ let forwarding_info = match channel. counterparty_forwarding_info {
1333+ Some ( info) => info,
1334+ None => continue ,
1335+ } ;
1336+ route_hints. push ( vec ! [ RouteHintHop {
1337+ src_node_id: channel. remote_network_id,
1338+ short_channel_id,
1339+ fees: RoutingFees {
1340+ base_msat: forwarding_info. fee_base_msat,
1341+ proportional_millionths: forwarding_info. fee_proportional_millionths,
1342+ } ,
1343+ cltv_expiry_delta: forwarding_info. cltv_expiry_delta,
1344+ htlc_minimum_msat: None ,
1345+ htlc_maximum_msat: None ,
1346+ } ] ) ;
1347+ }
1348+
1349+ let ( payment_hash, payment_secret) = channelmanager. create_inbound_payment (
1350+ amt_msat,
1351+ 7200 , // default invoice expiry is 2 hours
1352+ 0 ,
1353+ ) ;
1354+ let secp_ctx = Secp256k1 :: new ( ) ;
1355+ let our_node_pubkey = channelmanager. get_our_node_id ( ) ;
1356+ let mut invoice = InvoiceBuilder :: new ( network)
1357+ . description ( description)
1358+ . current_timestamp ( )
1359+ . payee_pub_key ( our_node_pubkey)
1360+ . payment_hash ( Hash :: from_slice ( & payment_hash. 0 ) . unwrap ( ) )
1361+ . payment_secret ( payment_secret)
1362+ . features ( InvoiceFeatures :: known ( ) )
1363+ . min_final_cltv_expiry ( MIN_FINAL_CLTV_EXPIRY . into ( ) ) ;
1364+ if let Some ( amt) = amt_msat {
1365+ invoice = invoice. amount_pico_btc ( amt * 10 ) ;
1366+ }
1367+ for hint in route_hints. drain ( ..) {
1368+ invoice = invoice. route ( hint) ;
1369+ }
1370+
1371+ invoice. build_signed ( |msg_hash| {
1372+ secp_ctx. sign_recoverable ( msg_hash, & channelmanager. get_our_node_secret ( ) )
1373+ } )
1374+ }
1375+
1376+ }
1377+
12951378#[ cfg( test) ]
12961379mod test {
12971380 use bitcoin_hashes:: hex:: FromHex ;
12981381 use bitcoin_hashes:: sha256;
1382+ use { Currency , Description , InvoiceDescription } ;
1383+ use lightning:: ln:: PaymentHash ;
1384+ use lightning:: ln:: functional_test_utils:: * ;
1385+ use lightning:: ln:: features:: InitFeatures ;
1386+ use lightning:: ln:: msgs:: ChannelMessageHandler ;
1387+ use lightning:: routing:: network_graph:: RoutingFees ;
1388+ use lightning:: routing:: router;
1389+ use lightning:: util:: events:: MessageSendEventsProvider ;
1390+ use lightning:: util:: test_utils;
12991391
13001392 #[ test]
13011393 fn test_system_time_bounds_assumptions ( ) {
@@ -1600,4 +1692,60 @@ mod test {
16001692 let raw_invoice = builder. build_raw ( ) . unwrap ( ) ;
16011693 assert_eq ! ( raw_invoice, * invoice. into_signed_raw( ) . raw_invoice( ) )
16021694 }
1695+
1696+ #[ test]
1697+ fn test_from_channelmanager ( ) {
1698+ let chanmon_cfgs = create_chanmon_cfgs ( 2 ) ;
1699+ let node_cfgs = create_node_cfgs ( 2 , & chanmon_cfgs) ;
1700+ let node_chanmgrs = create_node_chanmgrs ( 2 , & node_cfgs, & [ None , None ] ) ;
1701+ let nodes = create_network ( 2 , & node_cfgs, & node_chanmgrs) ;
1702+ let _chan = create_announced_chan_between_nodes ( & nodes, 0 , 1 , InitFeatures :: known ( ) , InitFeatures :: known ( ) ) ;
1703+ let invoice = :: utils:: create_invoice_from_channelmanager ( & nodes[ 1 ] . node , Some ( 10_000 ) , "test" . to_string ( ) , Currency :: BitcoinTestnet ) . unwrap ( ) ;
1704+ assert_eq ! ( invoice. amount_pico_btc( ) , Some ( 100_000 ) ) ;
1705+ assert_eq ! ( invoice. min_final_cltv_expiry( ) , Some ( & 9 ) ) ;
1706+ assert_eq ! ( invoice. description( ) , InvoiceDescription :: Direct ( & Description ( "test" . to_string( ) ) ) ) ;
1707+
1708+ let mut route_hints = invoice. routes ( ) . clone ( ) ;
1709+ let mut last_hops = Vec :: new ( ) ;
1710+ for hint in route_hints. drain ( ..) {
1711+ last_hops. push ( hint[ hint. len ( ) - 1 ] . clone ( ) ) ;
1712+ }
1713+ let amt_msat = invoice. amount_pico_btc ( ) . unwrap ( ) / 10 ;
1714+
1715+ let first_hops = nodes[ 0 ] . node . list_usable_channels ( ) ;
1716+ let network_graph = nodes[ 0 ] . net_graph_msg_handler . network_graph . read ( ) . unwrap ( ) ;
1717+ let logger = test_utils:: TestLogger :: new ( ) ;
1718+ let route = router:: get_route (
1719+ & nodes[ 0 ] . node . get_our_node_id ( ) ,
1720+ & network_graph,
1721+ & invoice. recover_payee_pub_key ( ) ,
1722+ Some ( invoice. features ( ) . unwrap ( ) . clone ( ) ) ,
1723+ Some ( & first_hops. iter ( ) . collect :: < Vec < _ > > ( ) ) ,
1724+ & last_hops. iter ( ) . collect :: < Vec < _ > > ( ) ,
1725+ amt_msat,
1726+ * invoice. min_final_cltv_expiry ( ) . unwrap ( ) as u32 ,
1727+ & logger,
1728+ ) . unwrap ( ) ;
1729+
1730+ let payment_event = {
1731+ let mut payment_hash = PaymentHash ( [ 0 ; 32 ] ) ;
1732+ payment_hash. 0 . copy_from_slice ( & invoice. payment_hash ( ) . as_ref ( ) [ 0 ..32 ] ) ;
1733+ nodes[ 0 ] . node . send_payment ( & route, payment_hash, & Some ( invoice. payment_secret ( ) . unwrap ( ) . clone ( ) ) ) . unwrap ( ) ;
1734+ let mut added_monitors = nodes[ 0 ] . chain_monitor . added_monitors . lock ( ) . unwrap ( ) ;
1735+ assert_eq ! ( added_monitors. len( ) , 1 ) ;
1736+ added_monitors. clear ( ) ;
1737+
1738+ let mut events = nodes[ 0 ] . node . get_and_clear_pending_msg_events ( ) ;
1739+ assert_eq ! ( events. len( ) , 1 ) ;
1740+ SendEvent :: from_event ( events. remove ( 0 ) )
1741+
1742+ } ;
1743+ nodes[ 1 ] . node . handle_update_add_htlc ( & nodes[ 0 ] . node . get_our_node_id ( ) , & payment_event. msgs [ 0 ] ) ;
1744+ nodes[ 1 ] . node . handle_commitment_signed ( & nodes[ 0 ] . node . get_our_node_id ( ) , & payment_event. commitment_msg ) ;
1745+ let mut added_monitors = nodes[ 1 ] . chain_monitor . added_monitors . lock ( ) . unwrap ( ) ;
1746+ assert_eq ! ( added_monitors. len( ) , 1 ) ;
1747+ added_monitors. clear ( ) ;
1748+ let events = nodes[ 1 ] . node . get_and_clear_pending_msg_events ( ) ;
1749+ assert_eq ! ( events. len( ) , 2 ) ;
1750+ }
16031751}
0 commit comments