@@ -2976,3 +2976,266 @@ async fn onchain_wallet_sync_cbf_reorgs_out_confirmed_receive() {
29762976
29772977 node. stop ( ) . unwrap ( ) ;
29782978}
2979+
2980+ #[ tokio:: test( flavor = "multi_thread" , worker_threads = 1 ) ]
2981+ async fn start_stop_reinit_cbf ( ) {
2982+ let ( bitcoind, electrsd) = setup_bitcoind_and_electrsd ( ) ;
2983+ let config = random_config ( true ) ;
2984+
2985+ let p2p_socket = bitcoind. params . p2p_socket . expect ( "P2P must be enabled for CBF" ) ;
2986+ let peer_addr = format ! ( "{}" , p2p_socket) ;
2987+ let sync_config = ldk_node:: config:: CbfSyncConfig {
2988+ background_sync_config : None ,
2989+ timeouts_config : Default :: default ( ) ,
2990+ } ;
2991+
2992+ let test_sync_store = TestSyncStore :: new ( config. node_config . storage_dir_path . clone ( ) . into ( ) ) ;
2993+
2994+ setup_builder ! ( builder, config. node_config) ;
2995+ builder. set_chain_source_cbf ( vec ! [ peer_addr. clone( ) ] , Some ( sync_config. clone ( ) ) ) ;
2996+
2997+ let node = builder
2998+ . build_with_store ( config. node_entropy . clone ( ) . into ( ) , test_sync_store. clone ( ) )
2999+ . unwrap ( ) ;
3000+ node. start ( ) . unwrap ( ) ;
3001+
3002+ let expected_node_id = node. node_id ( ) ;
3003+ assert_eq ! ( node. start( ) , Err ( NodeError :: AlreadyRunning ) ) ;
3004+
3005+ let funding_address = node. onchain_payment ( ) . new_address ( ) . unwrap ( ) ;
3006+ assert_eq ! ( node. list_balances( ) . total_onchain_balance_sats, 0 ) ;
3007+
3008+ let expected_amount = Amount :: from_sat ( 100_000 ) ;
3009+ premine_and_distribute_funds (
3010+ & bitcoind. client ,
3011+ & electrsd. client ,
3012+ vec ! [ funding_address] ,
3013+ expected_amount,
3014+ )
3015+ . await ;
3016+
3017+ wait_for_cbf_sync ( & node) . await ;
3018+ assert_eq ! ( node. list_balances( ) . spendable_onchain_balance_sats, expected_amount. to_sat( ) ) ;
3019+
3020+ node. stop ( ) . unwrap ( ) ;
3021+ assert_eq ! ( node. stop( ) , Err ( NodeError :: NotRunning ) ) ;
3022+
3023+ node. start ( ) . unwrap ( ) ;
3024+ assert_eq ! ( node. start( ) , Err ( NodeError :: AlreadyRunning ) ) ;
3025+
3026+ node. stop ( ) . unwrap ( ) ;
3027+ assert_eq ! ( node. stop( ) , Err ( NodeError :: NotRunning ) ) ;
3028+ drop ( node) ;
3029+
3030+ // Reinitialize from the same config and store.
3031+ setup_builder ! ( builder, config. node_config) ;
3032+ builder. set_chain_source_cbf ( vec ! [ peer_addr] , Some ( sync_config) ) ;
3033+
3034+ let reinitialized_node =
3035+ builder. build_with_store ( config. node_entropy . into ( ) , test_sync_store) . unwrap ( ) ;
3036+ reinitialized_node. start ( ) . unwrap ( ) ;
3037+ assert_eq ! ( reinitialized_node. node_id( ) , expected_node_id) ;
3038+
3039+ // Balance should be persisted from the previous run.
3040+ assert_eq ! (
3041+ reinitialized_node. list_balances( ) . spendable_onchain_balance_sats,
3042+ expected_amount. to_sat( )
3043+ ) ;
3044+
3045+ wait_for_cbf_sync ( & reinitialized_node) . await ;
3046+ assert_eq ! (
3047+ reinitialized_node. list_balances( ) . spendable_onchain_balance_sats,
3048+ expected_amount. to_sat( )
3049+ ) ;
3050+
3051+ reinitialized_node. stop ( ) . unwrap ( ) ;
3052+ }
3053+
3054+ #[ tokio:: test( flavor = "multi_thread" , worker_threads = 1 ) ]
3055+ async fn onchain_wallet_recovery_cbf ( ) {
3056+ let ( bitcoind, electrsd) = setup_bitcoind_and_electrsd ( ) ;
3057+ let chain_source = TestChainSource :: Cbf ( & bitcoind) ;
3058+
3059+ let original_config = random_config ( true ) ;
3060+ let original_node_entropy = original_config. node_entropy . clone ( ) ;
3061+ let original_node = setup_node ( & chain_source, original_config) ;
3062+
3063+ let premine_amount_sat = 100_000 ;
3064+
3065+ let addr_1 = original_node. onchain_payment ( ) . new_address ( ) . unwrap ( ) ;
3066+
3067+ premine_and_distribute_funds (
3068+ & bitcoind. client ,
3069+ & electrsd. client ,
3070+ vec ! [ addr_1] ,
3071+ Amount :: from_sat ( premine_amount_sat) ,
3072+ )
3073+ . await ;
3074+
3075+ wait_for_cbf_sync ( & original_node) . await ;
3076+ assert_eq ! ( original_node. list_balances( ) . spendable_onchain_balance_sats, premine_amount_sat) ;
3077+
3078+ let addr_2 = original_node. onchain_payment ( ) . new_address ( ) . unwrap ( ) ;
3079+
3080+ let txid = bitcoind
3081+ . client
3082+ . send_to_address ( & addr_2, Amount :: from_sat ( premine_amount_sat) )
3083+ . unwrap ( )
3084+ . 0
3085+ . parse ( )
3086+ . unwrap ( ) ;
3087+ wait_for_tx ( & electrsd. client , txid) . await ;
3088+
3089+ generate_blocks_and_wait ( & bitcoind. client , & electrsd. client , 1 ) . await ;
3090+
3091+ wait_for_cbf_sync ( & original_node) . await ;
3092+ assert_eq ! (
3093+ original_node. list_balances( ) . spendable_onchain_balance_sats,
3094+ premine_amount_sat * 2
3095+ ) ;
3096+
3097+ original_node. stop ( ) . unwrap ( ) ;
3098+ drop ( original_node) ;
3099+
3100+ // Now we start from scratch, only the seed remains the same.
3101+ let mut recovered_config = random_config ( true ) ;
3102+ recovered_config. node_entropy = original_node_entropy;
3103+ recovered_config. recovery_mode = true ;
3104+ let recovered_node = setup_node ( & chain_source, recovered_config) ;
3105+
3106+ wait_for_cbf_sync ( & recovered_node) . await ;
3107+ assert_eq ! (
3108+ recovered_node. list_balances( ) . spendable_onchain_balance_sats,
3109+ premine_amount_sat * 2
3110+ ) ;
3111+
3112+ // Check we sync even when skipping some addresses.
3113+ let _addr_3 = recovered_node. onchain_payment ( ) . new_address ( ) . unwrap ( ) ;
3114+ let _addr_4 = recovered_node. onchain_payment ( ) . new_address ( ) . unwrap ( ) ;
3115+ let _addr_5 = recovered_node. onchain_payment ( ) . new_address ( ) . unwrap ( ) ;
3116+ let addr_6 = recovered_node. onchain_payment ( ) . new_address ( ) . unwrap ( ) ;
3117+
3118+ let txid = bitcoind
3119+ . client
3120+ . send_to_address ( & addr_6, Amount :: from_sat ( premine_amount_sat) )
3121+ . unwrap ( )
3122+ . 0
3123+ . parse ( )
3124+ . unwrap ( ) ;
3125+ wait_for_tx ( & electrsd. client , txid) . await ;
3126+
3127+ generate_blocks_and_wait ( & bitcoind. client , & electrsd. client , 1 ) . await ;
3128+
3129+ wait_for_cbf_sync ( & recovered_node) . await ;
3130+ assert_eq ! (
3131+ recovered_node. list_balances( ) . spendable_onchain_balance_sats,
3132+ premine_amount_sat * 3
3133+ ) ;
3134+
3135+ recovered_node. stop ( ) . unwrap ( ) ;
3136+ }
3137+
3138+ #[ tokio:: test( flavor = "multi_thread" , worker_threads = 1 ) ]
3139+ async fn onchain_send_receive_cbf ( ) {
3140+ let ( bitcoind, electrsd) = setup_bitcoind_and_electrsd ( ) ;
3141+ let chain_source = TestChainSource :: Cbf ( & bitcoind) ;
3142+ let ( node_a, node_b) = setup_two_nodes ( & chain_source, false , true , false ) ;
3143+
3144+ let addr_a = node_a. onchain_payment ( ) . new_address ( ) . unwrap ( ) ;
3145+ let addr_b = node_b. onchain_payment ( ) . new_address ( ) . unwrap ( ) ;
3146+
3147+ let premine_amount_sat = 1_100_000 ;
3148+ premine_and_distribute_funds (
3149+ & bitcoind. client ,
3150+ & electrsd. client ,
3151+ vec ! [ addr_a. clone( ) , addr_b. clone( ) ] ,
3152+ Amount :: from_sat ( premine_amount_sat) ,
3153+ )
3154+ . await ;
3155+
3156+ wait_for_cbf_sync ( & node_a) . await ;
3157+ node_b. sync_wallets ( ) . unwrap ( ) ;
3158+ assert_eq ! ( node_a. list_balances( ) . spendable_onchain_balance_sats, premine_amount_sat) ;
3159+ assert_eq ! ( node_b. list_balances( ) . spendable_onchain_balance_sats, premine_amount_sat) ;
3160+
3161+ // Check on-chain payment tracking after premine.
3162+ let node_a_payments = node_a. list_payments ( ) ;
3163+ let node_b_payments = node_b. list_payments ( ) ;
3164+ for payments in [ & node_a_payments, & node_b_payments] {
3165+ assert_eq ! ( payments. len( ) , 1 ) ;
3166+ }
3167+ for p in [ node_a_payments. first ( ) . unwrap ( ) , node_b_payments. first ( ) . unwrap ( ) ] {
3168+ assert_eq ! ( p. amount_msat, Some ( premine_amount_sat * 1000 ) ) ;
3169+ assert_eq ! ( p. direction, PaymentDirection :: Inbound ) ;
3170+ assert_eq ! ( p. status, PaymentStatus :: Pending ) ;
3171+ match p. kind {
3172+ PaymentKind :: Onchain { status, .. } => {
3173+ assert ! ( matches!( status, ConfirmationStatus :: Confirmed { .. } ) ) ;
3174+ } ,
3175+ _ => panic ! ( "Unexpected payment kind" ) ,
3176+ }
3177+ }
3178+
3179+ // Send from B to A.
3180+ let amount_to_send_sats = 54_321 ;
3181+ let txid =
3182+ node_b. onchain_payment ( ) . send_to_address ( & addr_a, amount_to_send_sats, None ) . unwrap ( ) ;
3183+ wait_for_tx ( & electrsd. client , txid) . await ;
3184+
3185+ // Mine the transaction so CBF can see it.
3186+ generate_blocks_and_wait ( & bitcoind. client , & electrsd. client , 6 ) . await ;
3187+ wait_for_cbf_sync ( & node_a) . await ;
3188+ node_b. sync_wallets ( ) . unwrap ( ) ;
3189+
3190+ let payment_id = PaymentId ( txid. to_byte_array ( ) ) ;
3191+ let payment_a = node_a. payment ( & payment_id) . unwrap ( ) ;
3192+ match payment_a. kind {
3193+ PaymentKind :: Onchain { txid : tx, status } => {
3194+ assert_eq ! ( tx, txid) ;
3195+ assert ! ( matches!( status, ConfirmationStatus :: Confirmed { .. } ) ) ;
3196+ } ,
3197+ _ => panic ! ( "Unexpected payment kind" ) ,
3198+ }
3199+ assert ! ( payment_a. fee_paid_msat > Some ( 0 ) ) ;
3200+ assert_eq ! ( payment_a. amount_msat, Some ( amount_to_send_sats * 1000 ) ) ;
3201+
3202+ let payment_b = node_b. payment ( & payment_id) . unwrap ( ) ;
3203+ match payment_b. kind {
3204+ PaymentKind :: Onchain { txid : tx, status } => {
3205+ assert_eq ! ( tx, txid) ;
3206+ assert ! ( matches!( status, ConfirmationStatus :: Confirmed { .. } ) ) ;
3207+ } ,
3208+ _ => panic ! ( "Unexpected payment kind" ) ,
3209+ }
3210+ assert ! ( payment_b. fee_paid_msat > Some ( 0 ) ) ;
3211+ assert_eq ! ( payment_b. amount_msat, Some ( amount_to_send_sats * 1000 ) ) ;
3212+ assert_eq ! ( payment_a. fee_paid_msat, payment_b. fee_paid_msat) ;
3213+
3214+ let onchain_fee_buffer_sat = 1000 ;
3215+ let expected_node_a_balance = premine_amount_sat + amount_to_send_sats;
3216+ assert_eq ! ( node_a. list_balances( ) . spendable_onchain_balance_sats, expected_node_a_balance) ;
3217+ assert ! (
3218+ node_b. list_balances( ) . spendable_onchain_balance_sats
3219+ > premine_amount_sat - amount_to_send_sats - onchain_fee_buffer_sat
3220+ ) ;
3221+ assert ! (
3222+ node_b. list_balances( ) . spendable_onchain_balance_sats
3223+ < premine_amount_sat - amount_to_send_sats
3224+ ) ;
3225+
3226+ // Test send_all_to_address.
3227+ let addr_b2 = node_b. onchain_payment ( ) . new_address ( ) . unwrap ( ) ;
3228+ let txid = node_a. onchain_payment ( ) . send_all_to_address ( & addr_b2, false , None ) . unwrap ( ) ;
3229+ wait_for_tx ( & electrsd. client , txid) . await ;
3230+
3231+ generate_blocks_and_wait ( & bitcoind. client , & electrsd. client , 6 ) . await ;
3232+ wait_for_cbf_sync ( & node_a) . await ;
3233+ node_b. sync_wallets ( ) . unwrap ( ) ;
3234+
3235+ assert_eq ! ( node_a. list_balances( ) . spendable_onchain_balance_sats, 0 ) ;
3236+ assert_eq ! ( node_a. list_balances( ) . total_onchain_balance_sats, 0 ) ;
3237+ assert ! ( node_b. list_balances( ) . spendable_onchain_balance_sats > premine_amount_sat) ;
3238+
3239+ node_a. stop ( ) . unwrap ( ) ;
3240+ node_b. stop ( ) . unwrap ( ) ;
3241+ }
0 commit comments