@@ -24,21 +24,19 @@ extern crate secp256k1;
24
24
use bech32:: u5;
25
25
use bitcoin_hashes:: Hash ;
26
26
use bitcoin_hashes:: sha256;
27
- use lightning:: ln:: features:: InvoiceFeatures ;
28
27
use lightning:: ln:: channelmanager:: PaymentSecret ;
29
- #[ cfg( any( doc, test) ) ]
30
- use lightning:: routing:: network_graph:: RoutingFees ;
28
+ use lightning:: ln:: features:: InvoiceFeatures ;
31
29
use lightning:: routing:: router:: RouteHintHop ;
32
30
33
31
use secp256k1:: key:: PublicKey ;
34
32
use secp256k1:: { Message , Secp256k1 } ;
35
33
use secp256k1:: recovery:: RecoverableSignature ;
36
- use std:: ops:: Deref ;
37
34
35
+ use std:: fmt:: { Display , Formatter , self } ;
38
36
use std:: iter:: FilterMap ;
37
+ use std:: ops:: Deref ;
39
38
use std:: slice:: Iter ;
40
39
use std:: time:: { SystemTime , Duration , UNIX_EPOCH } ;
41
- use std:: fmt:: { Display , Formatter , self } ;
42
40
43
41
mod de;
44
42
mod ser;
@@ -1292,10 +1290,104 @@ impl<S> Display for SignOrCreationError<S> {
1292
1290
}
1293
1291
}
1294
1292
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
+
1295
1378
#[ cfg( test) ]
1296
1379
mod test {
1297
1380
use bitcoin_hashes:: hex:: FromHex ;
1298
1381
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;
1299
1391
1300
1392
#[ test]
1301
1393
fn test_system_time_bounds_assumptions ( ) {
@@ -1600,4 +1692,60 @@ mod test {
1600
1692
let raw_invoice = builder. build_raw ( ) . unwrap ( ) ;
1601
1693
assert_eq ! ( raw_invoice, * invoice. into_signed_raw( ) . raw_invoice( ) )
1602
1694
}
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
+ }
1603
1751
}
0 commit comments