@@ -2877,3 +2877,266 @@ async fn repeated_manual_sync_cbf() {
28772877
28782878 node. stop ( ) . unwrap ( ) ;
28792879}
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 = ldk_node:: config:: CbfSyncConfig {
2889+ background_sync_config : None ,
2890+ timeouts_config : Default :: default ( ) ,
2891+ } ;
2892+
2893+ let test_sync_store = TestSyncStore :: new ( config. node_config . storage_dir_path . clone ( ) . into ( ) ) ;
2894+
2895+ setup_builder ! ( builder, config. node_config) ;
2896+ builder. set_chain_source_cbf ( vec ! [ peer_addr. clone( ) ] , Some ( sync_config. clone ( ) ) ) ;
2897+
2898+ let node = builder
2899+ . build_with_store ( config. node_entropy . clone ( ) . into ( ) , test_sync_store. clone ( ) )
2900+ . unwrap ( ) ;
2901+ node. start ( ) . unwrap ( ) ;
2902+
2903+ let expected_node_id = node. node_id ( ) ;
2904+ assert_eq ! ( node. start( ) , Err ( NodeError :: AlreadyRunning ) ) ;
2905+
2906+ let funding_address = node. onchain_payment ( ) . new_address ( ) . unwrap ( ) ;
2907+ assert_eq ! ( node. list_balances( ) . total_onchain_balance_sats, 0 ) ;
2908+
2909+ let expected_amount = Amount :: from_sat ( 100_000 ) ;
2910+ premine_and_distribute_funds (
2911+ & bitcoind. client ,
2912+ & electrsd. client ,
2913+ vec ! [ funding_address] ,
2914+ expected_amount,
2915+ )
2916+ . await ;
2917+
2918+ wait_for_cbf_sync ( & node) . await ;
2919+ assert_eq ! ( node. list_balances( ) . spendable_onchain_balance_sats, expected_amount. to_sat( ) ) ;
2920+
2921+ node. stop ( ) . unwrap ( ) ;
2922+ assert_eq ! ( node. stop( ) , Err ( NodeError :: NotRunning ) ) ;
2923+
2924+ node. start ( ) . unwrap ( ) ;
2925+ assert_eq ! ( node. start( ) , Err ( NodeError :: AlreadyRunning ) ) ;
2926+
2927+ node. stop ( ) . unwrap ( ) ;
2928+ assert_eq ! ( node. stop( ) , Err ( NodeError :: NotRunning ) ) ;
2929+ drop ( node) ;
2930+
2931+ // Reinitialize from the same config and store.
2932+ setup_builder ! ( builder, config. node_config) ;
2933+ builder. set_chain_source_cbf ( vec ! [ peer_addr] , Some ( sync_config) ) ;
2934+
2935+ let reinitialized_node =
2936+ builder. build_with_store ( config. node_entropy . into ( ) , test_sync_store) . unwrap ( ) ;
2937+ reinitialized_node. start ( ) . unwrap ( ) ;
2938+ assert_eq ! ( reinitialized_node. node_id( ) , expected_node_id) ;
2939+
2940+ // Balance should be persisted from the previous run.
2941+ assert_eq ! (
2942+ reinitialized_node. list_balances( ) . spendable_onchain_balance_sats,
2943+ expected_amount. to_sat( )
2944+ ) ;
2945+
2946+ wait_for_cbf_sync ( & reinitialized_node) . await ;
2947+ assert_eq ! (
2948+ reinitialized_node. list_balances( ) . spendable_onchain_balance_sats,
2949+ expected_amount. to_sat( )
2950+ ) ;
2951+
2952+ reinitialized_node. stop ( ) . unwrap ( ) ;
2953+ }
2954+
2955+ #[ tokio:: test( flavor = "multi_thread" , worker_threads = 1 ) ]
2956+ async fn onchain_wallet_recovery_cbf ( ) {
2957+ let ( bitcoind, electrsd) = setup_bitcoind_and_electrsd ( ) ;
2958+ let chain_source = TestChainSource :: Cbf ( & bitcoind) ;
2959+
2960+ let original_config = random_config ( true ) ;
2961+ let original_node_entropy = original_config. node_entropy . clone ( ) ;
2962+ let original_node = setup_node ( & chain_source, original_config) ;
2963+
2964+ let premine_amount_sat = 100_000 ;
2965+
2966+ let addr_1 = original_node. onchain_payment ( ) . new_address ( ) . unwrap ( ) ;
2967+
2968+ premine_and_distribute_funds (
2969+ & bitcoind. client ,
2970+ & electrsd. client ,
2971+ vec ! [ addr_1] ,
2972+ Amount :: from_sat ( premine_amount_sat) ,
2973+ )
2974+ . await ;
2975+
2976+ wait_for_cbf_sync ( & original_node) . await ;
2977+ assert_eq ! ( original_node. list_balances( ) . spendable_onchain_balance_sats, premine_amount_sat) ;
2978+
2979+ let addr_2 = original_node. onchain_payment ( ) . new_address ( ) . unwrap ( ) ;
2980+
2981+ let txid = bitcoind
2982+ . client
2983+ . send_to_address ( & addr_2, Amount :: from_sat ( premine_amount_sat) )
2984+ . unwrap ( )
2985+ . 0
2986+ . parse ( )
2987+ . unwrap ( ) ;
2988+ wait_for_tx ( & electrsd. client , txid) . await ;
2989+
2990+ generate_blocks_and_wait ( & bitcoind. client , & electrsd. client , 1 ) . await ;
2991+
2992+ wait_for_cbf_sync ( & original_node) . await ;
2993+ assert_eq ! (
2994+ original_node. list_balances( ) . spendable_onchain_balance_sats,
2995+ premine_amount_sat * 2
2996+ ) ;
2997+
2998+ original_node. stop ( ) . unwrap ( ) ;
2999+ drop ( original_node) ;
3000+
3001+ // Now we start from scratch, only the seed remains the same.
3002+ let mut recovered_config = random_config ( true ) ;
3003+ recovered_config. node_entropy = original_node_entropy;
3004+ recovered_config. recovery_mode = true ;
3005+ let recovered_node = setup_node ( & chain_source, recovered_config) ;
3006+
3007+ wait_for_cbf_sync ( & recovered_node) . await ;
3008+ assert_eq ! (
3009+ recovered_node. list_balances( ) . spendable_onchain_balance_sats,
3010+ premine_amount_sat * 2
3011+ ) ;
3012+
3013+ // Check we sync even when skipping some addresses.
3014+ let _addr_3 = recovered_node. onchain_payment ( ) . new_address ( ) . unwrap ( ) ;
3015+ let _addr_4 = recovered_node. onchain_payment ( ) . new_address ( ) . unwrap ( ) ;
3016+ let _addr_5 = recovered_node. onchain_payment ( ) . new_address ( ) . unwrap ( ) ;
3017+ let addr_6 = recovered_node. onchain_payment ( ) . new_address ( ) . unwrap ( ) ;
3018+
3019+ let txid = bitcoind
3020+ . client
3021+ . send_to_address ( & addr_6, Amount :: from_sat ( premine_amount_sat) )
3022+ . unwrap ( )
3023+ . 0
3024+ . parse ( )
3025+ . unwrap ( ) ;
3026+ wait_for_tx ( & electrsd. client , txid) . await ;
3027+
3028+ generate_blocks_and_wait ( & bitcoind. client , & electrsd. client , 1 ) . await ;
3029+
3030+ wait_for_cbf_sync ( & recovered_node) . await ;
3031+ assert_eq ! (
3032+ recovered_node. list_balances( ) . spendable_onchain_balance_sats,
3033+ premine_amount_sat * 3
3034+ ) ;
3035+
3036+ recovered_node. stop ( ) . unwrap ( ) ;
3037+ }
3038+
3039+ #[ tokio:: test( flavor = "multi_thread" , worker_threads = 1 ) ]
3040+ async fn onchain_send_receive_cbf ( ) {
3041+ let ( bitcoind, electrsd) = setup_bitcoind_and_electrsd ( ) ;
3042+ let chain_source = TestChainSource :: Cbf ( & bitcoind) ;
3043+ let ( node_a, node_b) = setup_two_nodes ( & chain_source, false , true , false ) ;
3044+
3045+ let addr_a = node_a. onchain_payment ( ) . new_address ( ) . unwrap ( ) ;
3046+ let addr_b = node_b. onchain_payment ( ) . new_address ( ) . unwrap ( ) ;
3047+
3048+ let premine_amount_sat = 1_100_000 ;
3049+ premine_and_distribute_funds (
3050+ & bitcoind. client ,
3051+ & electrsd. client ,
3052+ vec ! [ addr_a. clone( ) , addr_b. clone( ) ] ,
3053+ Amount :: from_sat ( premine_amount_sat) ,
3054+ )
3055+ . await ;
3056+
3057+ wait_for_cbf_sync ( & node_a) . await ;
3058+ node_b. sync_wallets ( ) . unwrap ( ) ;
3059+ assert_eq ! ( node_a. list_balances( ) . spendable_onchain_balance_sats, premine_amount_sat) ;
3060+ assert_eq ! ( node_b. list_balances( ) . spendable_onchain_balance_sats, premine_amount_sat) ;
3061+
3062+ // Check on-chain payment tracking after premine.
3063+ let node_a_payments = node_a. list_payments ( ) ;
3064+ let node_b_payments = node_b. list_payments ( ) ;
3065+ for payments in [ & node_a_payments, & node_b_payments] {
3066+ assert_eq ! ( payments. len( ) , 1 ) ;
3067+ }
3068+ for p in [ node_a_payments. first ( ) . unwrap ( ) , node_b_payments. first ( ) . unwrap ( ) ] {
3069+ assert_eq ! ( p. amount_msat, Some ( premine_amount_sat * 1000 ) ) ;
3070+ assert_eq ! ( p. direction, PaymentDirection :: Inbound ) ;
3071+ assert_eq ! ( p. status, PaymentStatus :: Pending ) ;
3072+ match p. kind {
3073+ PaymentKind :: Onchain { status, .. } => {
3074+ assert ! ( matches!( status, ConfirmationStatus :: Confirmed { .. } ) ) ;
3075+ } ,
3076+ _ => panic ! ( "Unexpected payment kind" ) ,
3077+ }
3078+ }
3079+
3080+ // Send from B to A.
3081+ let amount_to_send_sats = 54_321 ;
3082+ let txid =
3083+ node_b. onchain_payment ( ) . send_to_address ( & addr_a, amount_to_send_sats, None ) . unwrap ( ) ;
3084+ wait_for_tx ( & electrsd. client , txid) . await ;
3085+
3086+ // Mine the transaction so CBF can see it.
3087+ generate_blocks_and_wait ( & bitcoind. client , & electrsd. client , 6 ) . await ;
3088+ wait_for_cbf_sync ( & node_a) . await ;
3089+ node_b. sync_wallets ( ) . unwrap ( ) ;
3090+
3091+ let payment_id = PaymentId ( txid. to_byte_array ( ) ) ;
3092+ let payment_a = node_a. payment ( & payment_id) . unwrap ( ) ;
3093+ match payment_a. kind {
3094+ PaymentKind :: Onchain { txid : tx, status } => {
3095+ assert_eq ! ( tx, txid) ;
3096+ assert ! ( matches!( status, ConfirmationStatus :: Confirmed { .. } ) ) ;
3097+ } ,
3098+ _ => panic ! ( "Unexpected payment kind" ) ,
3099+ }
3100+ assert ! ( payment_a. fee_paid_msat > Some ( 0 ) ) ;
3101+ assert_eq ! ( payment_a. amount_msat, Some ( amount_to_send_sats * 1000 ) ) ;
3102+
3103+ let payment_b = node_b. payment ( & payment_id) . unwrap ( ) ;
3104+ match payment_b. kind {
3105+ PaymentKind :: Onchain { txid : tx, status } => {
3106+ assert_eq ! ( tx, txid) ;
3107+ assert ! ( matches!( status, ConfirmationStatus :: Confirmed { .. } ) ) ;
3108+ } ,
3109+ _ => panic ! ( "Unexpected payment kind" ) ,
3110+ }
3111+ assert ! ( payment_b. fee_paid_msat > Some ( 0 ) ) ;
3112+ assert_eq ! ( payment_b. amount_msat, Some ( amount_to_send_sats * 1000 ) ) ;
3113+ assert_eq ! ( payment_a. fee_paid_msat, payment_b. fee_paid_msat) ;
3114+
3115+ let onchain_fee_buffer_sat = 1000 ;
3116+ let expected_node_a_balance = premine_amount_sat + amount_to_send_sats;
3117+ assert_eq ! ( node_a. list_balances( ) . spendable_onchain_balance_sats, expected_node_a_balance) ;
3118+ assert ! (
3119+ node_b. list_balances( ) . spendable_onchain_balance_sats
3120+ > premine_amount_sat - amount_to_send_sats - onchain_fee_buffer_sat
3121+ ) ;
3122+ assert ! (
3123+ node_b. list_balances( ) . spendable_onchain_balance_sats
3124+ < premine_amount_sat - amount_to_send_sats
3125+ ) ;
3126+
3127+ // Test send_all_to_address.
3128+ let addr_b2 = node_b. onchain_payment ( ) . new_address ( ) . unwrap ( ) ;
3129+ let txid = node_a. onchain_payment ( ) . send_all_to_address ( & addr_b2, false , None ) . unwrap ( ) ;
3130+ wait_for_tx ( & electrsd. client , txid) . await ;
3131+
3132+ generate_blocks_and_wait ( & bitcoind. client , & electrsd. client , 6 ) . await ;
3133+ wait_for_cbf_sync ( & node_a) . await ;
3134+ node_b. sync_wallets ( ) . unwrap ( ) ;
3135+
3136+ assert_eq ! ( node_a. list_balances( ) . spendable_onchain_balance_sats, 0 ) ;
3137+ assert_eq ! ( node_a. list_balances( ) . total_onchain_balance_sats, 0 ) ;
3138+ assert ! ( node_b. list_balances( ) . spendable_onchain_balance_sats > premine_amount_sat) ;
3139+
3140+ node_a. stop ( ) . unwrap ( ) ;
3141+ node_b. stop ( ) . unwrap ( ) ;
3142+ }
0 commit comments