@@ -24,7 +24,7 @@ use common::{
2424 open_channel, open_channel_push_amt, open_channel_with_all, premine_and_distribute_funds,
2525 premine_blocks, prepare_rbf, random_chain_source, random_config, random_listening_addresses,
2626 setup_bitcoind_and_electrsd, setup_builder, setup_node, setup_two_nodes, splice_in_with_all,
27- wait_for_tx, TestChainSource , TestStoreType , TestSyncStore ,
27+ wait_for_cbf_sync , wait_for_tx, TestChainSource , TestStoreType , TestSyncStore ,
2828} ;
2929use ldk_node:: config:: { AsyncPaymentsRole , EsploraSyncConfig } ;
3030use ldk_node:: entropy:: NodeEntropy ;
@@ -2805,3 +2805,336 @@ async fn splice_in_with_all_balance() {
28052805 node_a. stop ( ) . unwrap ( ) ;
28062806 node_b. stop ( ) . unwrap ( ) ;
28072807}
2808+
2809+ #[ tokio:: test( flavor = "multi_thread" , worker_threads = 1 ) ]
2810+ async fn start_stop_cbf ( ) {
2811+ let ( bitcoind, _electrsd) = setup_bitcoind_and_electrsd ( ) ;
2812+ let chain_source = TestChainSource :: Cbf ( & bitcoind) ;
2813+ let node = setup_node ( & chain_source, random_config ( true ) ) ;
2814+
2815+ assert ! ( node. status( ) . is_running) ;
2816+ node. stop ( ) . unwrap ( ) ;
2817+ assert_eq ! ( node. stop( ) , Err ( NodeError :: NotRunning ) ) ;
2818+
2819+ node. start ( ) . unwrap ( ) ;
2820+ assert_eq ! ( node. start( ) , Err ( NodeError :: AlreadyRunning ) ) ;
2821+ assert ! ( node. status( ) . is_running) ;
2822+
2823+ node. stop ( ) . unwrap ( ) ;
2824+ }
2825+
2826+ #[ tokio:: test( flavor = "multi_thread" , worker_threads = 1 ) ]
2827+ async fn fee_rate_estimation_after_manual_sync_cbf ( ) {
2828+ let ( bitcoind, electrsd) = setup_bitcoind_and_electrsd ( ) ;
2829+ let chain_source = TestChainSource :: Cbf ( & bitcoind) ;
2830+ let node = setup_node ( & chain_source, random_config ( true ) ) ;
2831+
2832+ let addr = node. onchain_payment ( ) . new_address ( ) . unwrap ( ) ;
2833+ premine_and_distribute_funds (
2834+ & bitcoind. client ,
2835+ & electrsd. client ,
2836+ vec ! [ addr] ,
2837+ Amount :: from_sat ( 100_000 ) ,
2838+ )
2839+ . await ;
2840+
2841+ wait_for_cbf_sync ( & node) . await ;
2842+ let first_fee_update = node. status ( ) . latest_fee_rate_cache_update_timestamp ;
2843+ assert ! ( first_fee_update. is_some( ) ) ;
2844+
2845+ // Subsequent manual syncs should keep the fee cache populated.
2846+ node. sync_wallets ( ) . unwrap ( ) ;
2847+ let second_fee_update = node. status ( ) . latest_fee_rate_cache_update_timestamp ;
2848+ assert ! ( second_fee_update. is_some( ) ) ;
2849+ assert ! ( second_fee_update >= first_fee_update) ;
2850+
2851+ node. stop ( ) . unwrap ( ) ;
2852+ }
2853+
2854+ #[ tokio:: test( flavor = "multi_thread" , worker_threads = 1 ) ]
2855+ async fn repeated_manual_sync_cbf ( ) {
2856+ let ( bitcoind, electrsd) = setup_bitcoind_and_electrsd ( ) ;
2857+ let chain_source = TestChainSource :: Cbf ( & bitcoind) ;
2858+ let node = setup_node ( & chain_source, random_config ( true ) ) ;
2859+
2860+ let addr = node. onchain_payment ( ) . new_address ( ) . unwrap ( ) ;
2861+ let premine_amount_sat = 100_000 ;
2862+
2863+ premine_and_distribute_funds (
2864+ & bitcoind. client ,
2865+ & electrsd. client ,
2866+ vec ! [ addr] ,
2867+ Amount :: from_sat ( premine_amount_sat) ,
2868+ )
2869+ . await ;
2870+
2871+ wait_for_cbf_sync ( & node) . await ;
2872+ assert_eq ! ( node. list_balances( ) . spendable_onchain_balance_sats, premine_amount_sat) ;
2873+
2874+ // Regression: the second manual sync must not block forever.
2875+ node. sync_wallets ( ) . unwrap ( ) ;
2876+ assert_eq ! ( node. list_balances( ) . spendable_onchain_balance_sats, premine_amount_sat) ;
2877+
2878+ node. stop ( ) . unwrap ( ) ;
2879+ }
2880+
2881+ #[ tokio:: test( flavor = "multi_thread" , worker_threads = 1 ) ]
2882+ async fn start_stop_reinit_cbf ( ) {
2883+ let ( bitcoind, electrsd) = setup_bitcoind_and_electrsd ( ) ;
2884+ let config = random_config ( true ) ;
2885+
2886+ let p2p_socket = bitcoind. params . p2p_socket . expect ( "P2P must be enabled for CBF" ) ;
2887+ let peer_addr = format ! ( "{}" , p2p_socket) ;
2888+ let sync_config =
2889+ ldk_node:: config:: CbfSyncConfig { background_sync_config : None , ..Default :: default ( ) } ;
2890+
2891+ let test_sync_store = TestSyncStore :: new ( config. node_config . storage_dir_path . clone ( ) . into ( ) ) ;
2892+
2893+ setup_builder ! ( builder, config. node_config) ;
2894+ builder. set_chain_source_cbf ( vec ! [ peer_addr. clone( ) ] , Some ( sync_config. clone ( ) ) ) ;
2895+
2896+ let node = builder
2897+ . build_with_store ( config. node_entropy . clone ( ) . into ( ) , test_sync_store. clone ( ) )
2898+ . unwrap ( ) ;
2899+ node. start ( ) . unwrap ( ) ;
2900+
2901+ let expected_node_id = node. node_id ( ) ;
2902+ assert_eq ! ( node. start( ) , Err ( NodeError :: AlreadyRunning ) ) ;
2903+
2904+ let funding_address = node. onchain_payment ( ) . new_address ( ) . unwrap ( ) ;
2905+ assert_eq ! ( node. list_balances( ) . total_onchain_balance_sats, 0 ) ;
2906+
2907+ let expected_amount = Amount :: from_sat ( 100_000 ) ;
2908+ premine_and_distribute_funds (
2909+ & bitcoind. client ,
2910+ & electrsd. client ,
2911+ vec ! [ funding_address] ,
2912+ expected_amount,
2913+ )
2914+ . await ;
2915+
2916+ wait_for_cbf_sync ( & node) . await ;
2917+ assert_eq ! ( node. list_balances( ) . spendable_onchain_balance_sats, expected_amount. to_sat( ) ) ;
2918+
2919+ node. stop ( ) . unwrap ( ) ;
2920+ assert_eq ! ( node. stop( ) , Err ( NodeError :: NotRunning ) ) ;
2921+
2922+ node. start ( ) . unwrap ( ) ;
2923+ assert_eq ! ( node. start( ) , Err ( NodeError :: AlreadyRunning ) ) ;
2924+
2925+ node. stop ( ) . unwrap ( ) ;
2926+ assert_eq ! ( node. stop( ) , Err ( NodeError :: NotRunning ) ) ;
2927+ drop ( node) ;
2928+
2929+ // Reinitialize from the same config and store.
2930+ setup_builder ! ( builder, config. node_config) ;
2931+ builder. set_chain_source_cbf ( vec ! [ peer_addr] , Some ( sync_config) ) ;
2932+
2933+ let reinitialized_node =
2934+ builder. build_with_store ( config. node_entropy . into ( ) , test_sync_store) . unwrap ( ) ;
2935+ reinitialized_node. start ( ) . unwrap ( ) ;
2936+ assert_eq ! ( reinitialized_node. node_id( ) , expected_node_id) ;
2937+
2938+ // Balance should be persisted from the previous run.
2939+ assert_eq ! (
2940+ reinitialized_node. list_balances( ) . spendable_onchain_balance_sats,
2941+ expected_amount. to_sat( )
2942+ ) ;
2943+
2944+ wait_for_cbf_sync ( & reinitialized_node) . await ;
2945+ assert_eq ! (
2946+ reinitialized_node. list_balances( ) . spendable_onchain_balance_sats,
2947+ expected_amount. to_sat( )
2948+ ) ;
2949+
2950+ reinitialized_node. stop ( ) . unwrap ( ) ;
2951+ }
2952+
2953+ #[ tokio:: test( flavor = "multi_thread" , worker_threads = 1 ) ]
2954+ async fn onchain_wallet_recovery_cbf ( ) {
2955+ let ( bitcoind, electrsd) = setup_bitcoind_and_electrsd ( ) ;
2956+ let chain_source = TestChainSource :: Cbf ( & bitcoind) ;
2957+
2958+ let original_config = random_config ( true ) ;
2959+ let original_node_entropy = original_config. node_entropy . clone ( ) ;
2960+ let original_node = setup_node ( & chain_source, original_config) ;
2961+
2962+ let premine_amount_sat = 100_000 ;
2963+
2964+ let addr_1 = original_node. onchain_payment ( ) . new_address ( ) . unwrap ( ) ;
2965+
2966+ premine_and_distribute_funds (
2967+ & bitcoind. client ,
2968+ & electrsd. client ,
2969+ vec ! [ addr_1] ,
2970+ Amount :: from_sat ( premine_amount_sat) ,
2971+ )
2972+ . await ;
2973+
2974+ wait_for_cbf_sync ( & original_node) . await ;
2975+ assert_eq ! ( original_node. list_balances( ) . spendable_onchain_balance_sats, premine_amount_sat) ;
2976+
2977+ let addr_2 = original_node. onchain_payment ( ) . new_address ( ) . unwrap ( ) ;
2978+
2979+ let txid = bitcoind
2980+ . client
2981+ . send_to_address ( & addr_2, Amount :: from_sat ( premine_amount_sat) )
2982+ . unwrap ( )
2983+ . 0
2984+ . parse ( )
2985+ . unwrap ( ) ;
2986+ wait_for_tx ( & electrsd. client , txid) . await ;
2987+
2988+ generate_blocks_and_wait ( & bitcoind. client , & electrsd. client , 1 ) . await ;
2989+
2990+ wait_for_cbf_sync ( & original_node) . await ;
2991+ assert_eq ! (
2992+ original_node. list_balances( ) . spendable_onchain_balance_sats,
2993+ premine_amount_sat * 2
2994+ ) ;
2995+
2996+ original_node. stop ( ) . unwrap ( ) ;
2997+ drop ( original_node) ;
2998+
2999+ // Now we start from scratch, only the seed remains the same.
3000+ let mut recovered_config = random_config ( true ) ;
3001+ recovered_config. node_entropy = original_node_entropy;
3002+ recovered_config. recovery_mode = true ;
3003+ let recovered_node = setup_node ( & chain_source, recovered_config) ;
3004+
3005+ wait_for_cbf_sync ( & recovered_node) . await ;
3006+ assert_eq ! (
3007+ recovered_node. list_balances( ) . spendable_onchain_balance_sats,
3008+ premine_amount_sat * 2
3009+ ) ;
3010+
3011+ // Check we sync even when skipping some addresses.
3012+ let _addr_3 = recovered_node. onchain_payment ( ) . new_address ( ) . unwrap ( ) ;
3013+ let _addr_4 = recovered_node. onchain_payment ( ) . new_address ( ) . unwrap ( ) ;
3014+ let _addr_5 = recovered_node. onchain_payment ( ) . new_address ( ) . unwrap ( ) ;
3015+ let addr_6 = recovered_node. onchain_payment ( ) . new_address ( ) . unwrap ( ) ;
3016+
3017+ let txid = bitcoind
3018+ . client
3019+ . send_to_address ( & addr_6, Amount :: from_sat ( premine_amount_sat) )
3020+ . unwrap ( )
3021+ . 0
3022+ . parse ( )
3023+ . unwrap ( ) ;
3024+ wait_for_tx ( & electrsd. client , txid) . await ;
3025+
3026+ generate_blocks_and_wait ( & bitcoind. client , & electrsd. client , 1 ) . await ;
3027+
3028+ wait_for_cbf_sync ( & recovered_node) . await ;
3029+ assert_eq ! (
3030+ recovered_node. list_balances( ) . spendable_onchain_balance_sats,
3031+ premine_amount_sat * 3
3032+ ) ;
3033+
3034+ recovered_node. stop ( ) . unwrap ( ) ;
3035+ }
3036+
3037+ #[ tokio:: test( flavor = "multi_thread" , worker_threads = 1 ) ]
3038+ async fn onchain_send_receive_cbf ( ) {
3039+ let ( bitcoind, electrsd) = setup_bitcoind_and_electrsd ( ) ;
3040+ let chain_source = TestChainSource :: Cbf ( & bitcoind) ;
3041+ let ( node_a, node_b) = setup_two_nodes ( & chain_source, false , true , false ) ;
3042+
3043+ let addr_a = node_a. onchain_payment ( ) . new_address ( ) . unwrap ( ) ;
3044+ let addr_b = node_b. onchain_payment ( ) . new_address ( ) . unwrap ( ) ;
3045+
3046+ let premine_amount_sat = 1_100_000 ;
3047+ premine_and_distribute_funds (
3048+ & bitcoind. client ,
3049+ & electrsd. client ,
3050+ vec ! [ addr_a. clone( ) , addr_b. clone( ) ] ,
3051+ Amount :: from_sat ( premine_amount_sat) ,
3052+ )
3053+ . await ;
3054+
3055+ wait_for_cbf_sync ( & node_a) . await ;
3056+ node_b. sync_wallets ( ) . unwrap ( ) ;
3057+ assert_eq ! ( node_a. list_balances( ) . spendable_onchain_balance_sats, premine_amount_sat) ;
3058+ assert_eq ! ( node_b. list_balances( ) . spendable_onchain_balance_sats, premine_amount_sat) ;
3059+
3060+ // Check on-chain payment tracking after premine.
3061+ let node_a_payments = node_a. list_payments ( ) ;
3062+ let node_b_payments = node_b. list_payments ( ) ;
3063+ for payments in [ & node_a_payments, & node_b_payments] {
3064+ assert_eq ! ( payments. len( ) , 1 ) ;
3065+ }
3066+ for p in [ node_a_payments. first ( ) . unwrap ( ) , node_b_payments. first ( ) . unwrap ( ) ] {
3067+ assert_eq ! ( p. amount_msat, Some ( premine_amount_sat * 1000 ) ) ;
3068+ assert_eq ! ( p. direction, PaymentDirection :: Inbound ) ;
3069+ assert_eq ! ( p. status, PaymentStatus :: Pending ) ;
3070+ match p. kind {
3071+ PaymentKind :: Onchain { status, .. } => {
3072+ assert ! ( matches!( status, ConfirmationStatus :: Confirmed { .. } ) ) ;
3073+ } ,
3074+ _ => panic ! ( "Unexpected payment kind" ) ,
3075+ }
3076+ }
3077+
3078+ // Send from B to A.
3079+ let amount_to_send_sats = 54_321 ;
3080+ let txid =
3081+ node_b. onchain_payment ( ) . send_to_address ( & addr_a, amount_to_send_sats, None ) . unwrap ( ) ;
3082+ wait_for_tx ( & electrsd. client , txid) . await ;
3083+
3084+ // Mine the transaction so CBF can see it.
3085+ generate_blocks_and_wait ( & bitcoind. client , & electrsd. client , 6 ) . await ;
3086+ wait_for_cbf_sync ( & node_a) . await ;
3087+ node_b. sync_wallets ( ) . unwrap ( ) ;
3088+
3089+ let payment_id = PaymentId ( txid. to_byte_array ( ) ) ;
3090+ let payment_a = node_a. payment ( & payment_id) . unwrap ( ) ;
3091+ match payment_a. kind {
3092+ PaymentKind :: Onchain { txid : tx, status } => {
3093+ assert_eq ! ( tx, txid) ;
3094+ assert ! ( matches!( status, ConfirmationStatus :: Confirmed { .. } ) ) ;
3095+ } ,
3096+ _ => panic ! ( "Unexpected payment kind" ) ,
3097+ }
3098+ assert ! ( payment_a. fee_paid_msat > Some ( 0 ) ) ;
3099+ assert_eq ! ( payment_a. amount_msat, Some ( amount_to_send_sats * 1000 ) ) ;
3100+
3101+ let payment_b = node_b. payment ( & payment_id) . unwrap ( ) ;
3102+ match payment_b. kind {
3103+ PaymentKind :: Onchain { txid : tx, status } => {
3104+ assert_eq ! ( tx, txid) ;
3105+ assert ! ( matches!( status, ConfirmationStatus :: Confirmed { .. } ) ) ;
3106+ } ,
3107+ _ => panic ! ( "Unexpected payment kind" ) ,
3108+ }
3109+ assert ! ( payment_b. fee_paid_msat > Some ( 0 ) ) ;
3110+ assert_eq ! ( payment_b. amount_msat, Some ( amount_to_send_sats * 1000 ) ) ;
3111+ assert_eq ! ( payment_a. fee_paid_msat, payment_b. fee_paid_msat) ;
3112+
3113+ let onchain_fee_buffer_sat = 1000 ;
3114+ let expected_node_a_balance = premine_amount_sat + amount_to_send_sats;
3115+ assert_eq ! ( node_a. list_balances( ) . spendable_onchain_balance_sats, expected_node_a_balance) ;
3116+ assert ! (
3117+ node_b. list_balances( ) . spendable_onchain_balance_sats
3118+ > premine_amount_sat - amount_to_send_sats - onchain_fee_buffer_sat
3119+ ) ;
3120+ assert ! (
3121+ node_b. list_balances( ) . spendable_onchain_balance_sats
3122+ < premine_amount_sat - amount_to_send_sats
3123+ ) ;
3124+
3125+ // Test send_all_to_address.
3126+ let addr_b2 = node_b. onchain_payment ( ) . new_address ( ) . unwrap ( ) ;
3127+ let txid = node_a. onchain_payment ( ) . send_all_to_address ( & addr_b2, false , None ) . unwrap ( ) ;
3128+ wait_for_tx ( & electrsd. client , txid) . await ;
3129+
3130+ generate_blocks_and_wait ( & bitcoind. client , & electrsd. client , 6 ) . await ;
3131+ wait_for_cbf_sync ( & node_a) . await ;
3132+ node_b. sync_wallets ( ) . unwrap ( ) ;
3133+
3134+ assert_eq ! ( node_a. list_balances( ) . spendable_onchain_balance_sats, 0 ) ;
3135+ assert_eq ! ( node_a. list_balances( ) . total_onchain_balance_sats, 0 ) ;
3136+ assert ! ( node_b. list_balances( ) . spendable_onchain_balance_sats > premine_amount_sat) ;
3137+
3138+ node_a. stop ( ) . unwrap ( ) ;
3139+ node_b. stop ( ) . unwrap ( ) ;
3140+ }
0 commit comments