@@ -10,6 +10,7 @@ mod common;
1010use std:: collections:: HashSet ;
1111use std:: str:: FromStr ;
1212use std:: sync:: Arc ;
13+ use std:: time:: Instant ;
1314
1415use bitcoin:: address:: NetworkUnchecked ;
1516use bitcoin:: hashes:: sha256:: Hash as Sha256Hash ;
@@ -23,21 +24,24 @@ use common::{
2324 generate_blocks_and_wait, open_channel, open_channel_push_amt, premine_and_distribute_funds,
2425 premine_blocks, prepare_rbf, random_config, random_listening_addresses,
2526 setup_bitcoind_and_electrsd, setup_builder, setup_node, setup_node_for_async_payments,
26- setup_two_nodes, wait_for_tx, TestChainSource , TestSyncStore ,
27+ setup_two_nodes, setup_two_nodes_with_store , wait_for_tx, TestChainSource , TestSyncStore ,
2728} ;
2829use ldk_node:: config:: { AsyncPaymentsRole , EsploraSyncConfig } ;
2930use ldk_node:: liquidity:: LSPS2ServiceConfig ;
3031use ldk_node:: payment:: {
3132 ConfirmationStatus , PaymentDetails , PaymentDirection , PaymentKind , PaymentStatus ,
3233 QrPaymentResult ,
3334} ;
34- use ldk_node:: { Builder , DynStore , Event , NodeError } ;
35+ use ldk_node:: { Builder , DynStore , Event , Node , NodeError } ;
3536use lightning:: ln:: channelmanager:: PaymentId ;
3637use lightning:: routing:: gossip:: { NodeAlias , NodeId } ;
3738use lightning:: routing:: router:: RouteParametersConfig ;
39+ use lightning:: util:: hash_tables:: new_hash_map;
3840use lightning_invoice:: { Bolt11InvoiceDescription , Description } ;
3941use lightning_types:: payment:: { PaymentHash , PaymentPreimage } ;
4042use log:: LevelFilter ;
43+ use tokio:: sync:: Mutex ;
44+ use tokio:: task:: { self , JoinSet } ;
4145
4246#[ test]
4347fn channel_full_cycle ( ) {
@@ -1761,6 +1765,128 @@ fn facade_logging() {
17611765 }
17621766}
17631767
1768+ fn spawn_payment ( node_a : Arc < Node > , node_b : Arc < Node > , cur_id : u32 ) {
1769+ let mut preimage_bytes = [ 0u8 ; 32 ] ;
1770+
1771+ preimage_bytes[ 0 ..4 ] . copy_from_slice ( & cur_id. to_le_bytes ( ) ) ;
1772+
1773+ // Spawn each payment as a separate async task
1774+ task:: spawn ( async move {
1775+ println ! ( "Starting payment {}" , cur_id) ;
1776+ let custom_preimage = PaymentPreimage ( preimage_bytes) ;
1777+ let amount_msat = 10_000_000 ;
1778+
1779+ loop {
1780+ // Pre-check the HTLC slots to try to avoid the performance impact of a failed payment.
1781+ while node_a. list_channels ( ) [ 0 ] . next_outbound_htlc_limit_msat == 0 {
1782+ println ! ( "Waiting for HTLC slots to free up... ({})" , cur_id) ;
1783+ tokio:: time:: sleep ( std:: time:: Duration :: from_millis ( 100 ) ) . await ;
1784+ }
1785+
1786+ let payment_id = node_a. spontaneous_payment ( ) . send_with_preimage (
1787+ amount_msat,
1788+ node_b. node_id ( ) ,
1789+ custom_preimage,
1790+ None ,
1791+ ) ;
1792+
1793+ match payment_id {
1794+ Ok ( payment_id) => {
1795+ println ! ( "Awaiting payment {} ({})" , payment_id, cur_id) ;
1796+ break ;
1797+ } ,
1798+ Err ( e) => {
1799+ println ! ( "Payment attempt failed: {:?}, retrying... ({})" , e, cur_id) ;
1800+
1801+ tokio:: time:: sleep ( std:: time:: Duration :: from_millis ( 100 ) ) . await ;
1802+ } ,
1803+ }
1804+ }
1805+ } ) ;
1806+ }
1807+
1808+ #[ tokio:: test( flavor = "multi_thread" , worker_threads = 4 ) ]
1809+ async fn payment_benchmark ( ) {
1810+ let ( bitcoind, electrsd) = setup_bitcoind_and_electrsd ( ) ;
1811+ let chain_source = TestChainSource :: Esplora ( & electrsd) ;
1812+ let ( node_a, node_b) = setup_two_nodes_with_store (
1813+ & chain_source,
1814+ false ,
1815+ true ,
1816+ false ,
1817+ common:: TestStoreType :: Sqlite ,
1818+ ) ;
1819+
1820+ let address_a = node_a. onchain_payment ( ) . new_address ( ) . unwrap ( ) ;
1821+ let premine_sat = 25_000_000 ;
1822+ premine_and_distribute_funds (
1823+ & bitcoind. client ,
1824+ & electrsd. client ,
1825+ vec ! [ address_a] ,
1826+ Amount :: from_sat ( premine_sat) ,
1827+ ) ;
1828+ node_a. sync_wallets ( ) . unwrap ( ) ;
1829+ node_b. sync_wallets ( ) . unwrap ( ) ;
1830+ open_channel ( & node_a, & node_b, 16_000_000 , true , & electrsd) ;
1831+ generate_blocks_and_wait ( & bitcoind. client , & electrsd. client , 6 ) ;
1832+ node_a. sync_wallets ( ) . unwrap ( ) ;
1833+ node_b. sync_wallets ( ) . unwrap ( ) ;
1834+ expect_channel_ready_event ! ( node_a, node_b. node_id( ) ) ;
1835+ expect_channel_ready_event ! ( node_b, node_a. node_id( ) ) ;
1836+
1837+ let start = Instant :: now ( ) ;
1838+
1839+ let node_a = Arc :: new ( node_a) ;
1840+ let node_b = Arc :: new ( node_b) ;
1841+
1842+ let total_payments = 1000 ;
1843+ let max_in_flight = 20 ;
1844+
1845+ let mut cur_id = 0u32 ;
1846+ let mut in_flight = 0 ;
1847+ let mut success_count = 0 ;
1848+
1849+ while success_count < total_payments {
1850+ // Spawn new payments if we aren't at max in-flight and haven't sent all payments yet.
1851+ let to_spawn =
1852+ std:: cmp:: min ( max_in_flight - in_flight, total_payments - ( in_flight + success_count) ) ;
1853+
1854+ println ! (
1855+ "Spawning {} new payments ({} in flight, {} successes)" ,
1856+ to_spawn, in_flight, success_count
1857+ ) ;
1858+ for _ in 0 ..to_spawn {
1859+ spawn_payment ( node_a. clone ( ) , node_b. clone ( ) , cur_id) ;
1860+ cur_id += 1 ;
1861+ in_flight += 1 ;
1862+ }
1863+
1864+ match node_a. next_event_async ( ) . await {
1865+ Event :: PaymentSuccessful { payment_id, .. } => {
1866+ if let Some ( id) = payment_id {
1867+ success_count += 1 ;
1868+ in_flight -= 1 ;
1869+ println ! ( "Payment {:?} completed" , id) ;
1870+ } else {
1871+ println ! ( "Payment completed (no payment_id)" ) ;
1872+ }
1873+ } ,
1874+ Event :: PaymentFailed { payment_id, .. } => {
1875+ in_flight -= 1 ;
1876+ println ! ( "Payment {:?} failed" , payment_id) ;
1877+ } ,
1878+ ref e => {
1879+ println ! ( "Received non-payment event: {:?}" , e) ;
1880+ } ,
1881+ }
1882+
1883+ node_a. event_handled ( ) . unwrap ( ) ;
1884+ }
1885+
1886+ let duration = start. elapsed ( ) ;
1887+ println ! ( "Time elapsed: {:?}" , duration) ;
1888+ }
1889+
17641890#[ test]
17651891fn spontaneous_send_with_custom_preimage ( ) {
17661892 let ( bitcoind, electrsd) = setup_bitcoind_and_electrsd ( ) ;
0 commit comments