@@ -3048,3 +3048,280 @@ async fn onchain_wallet_sync_cbf_reorgs_out_confirmed_receive() {
30483048
30493049 node. stop ( ) . unwrap ( ) ;
30503050}
3051+
3052+ #[ cfg( feature = "cbf" ) ]
3053+ #[ tokio:: test( flavor = "multi_thread" , worker_threads = 1 ) ]
3054+ async fn start_stop_reinit_cbf ( ) {
3055+ let ( bitcoind, electrsd) = setup_bitcoind_and_electrsd ( ) ;
3056+ let config = random_config ( true ) ;
3057+
3058+ let p2p_socket = bitcoind. params . p2p_socket . expect ( "P2P must be enabled for CBF" ) ;
3059+ let peer_addr = format ! ( "{}" , p2p_socket) ;
3060+ let sync_config = ldk_node:: config:: CbfSyncConfig {
3061+ background_sync_config : None ,
3062+ timeouts_config : Default :: default ( ) ,
3063+ } ;
3064+
3065+ let test_sync_store = TestSyncStore :: new ( config. node_config . storage_dir_path . clone ( ) . into ( ) ) ;
3066+
3067+ setup_builder ! ( builder, config. node_config) ;
3068+ builder. set_chain_source_cbf ( vec ! [ peer_addr. clone( ) ] , Some ( sync_config. clone ( ) ) ) ;
3069+
3070+ let node = builder
3071+ . build_with_store ( config. node_entropy . clone ( ) . into ( ) , test_sync_store. clone ( ) )
3072+ . unwrap ( ) ;
3073+ node. start ( ) . unwrap ( ) ;
3074+
3075+ let expected_node_id = node. node_id ( ) ;
3076+ assert_eq ! ( node. start( ) , Err ( NodeError :: AlreadyRunning ) ) ;
3077+
3078+ let funding_address = node. onchain_payment ( ) . new_address ( ) . unwrap ( ) ;
3079+ assert_eq ! ( node. list_balances( ) . total_onchain_balance_sats, 0 ) ;
3080+
3081+ let expected_amount = Amount :: from_sat ( 100_000 ) ;
3082+ premine_and_distribute_funds (
3083+ & bitcoind. client ,
3084+ & electrsd. client ,
3085+ vec ! [ funding_address] ,
3086+ expected_amount,
3087+ )
3088+ . await ;
3089+
3090+ wait_for_cbf_filters ( ) . await ;
3091+ node. sync_wallets ( ) . unwrap ( ) ;
3092+ assert_eq ! ( node. list_balances( ) . spendable_onchain_balance_sats, expected_amount. to_sat( ) ) ;
3093+
3094+ node. stop ( ) . unwrap ( ) ;
3095+ assert_eq ! ( node. stop( ) , Err ( NodeError :: NotRunning ) ) ;
3096+
3097+ node. start ( ) . unwrap ( ) ;
3098+ assert_eq ! ( node. start( ) , Err ( NodeError :: AlreadyRunning ) ) ;
3099+
3100+ node. stop ( ) . unwrap ( ) ;
3101+ assert_eq ! ( node. stop( ) , Err ( NodeError :: NotRunning ) ) ;
3102+ drop ( node) ;
3103+
3104+ // Reinitialize from the same config and store.
3105+ setup_builder ! ( builder, config. node_config) ;
3106+ builder. set_chain_source_cbf ( vec ! [ peer_addr] , Some ( sync_config) ) ;
3107+
3108+ let reinitialized_node =
3109+ builder. build_with_store ( config. node_entropy . into ( ) , test_sync_store) . unwrap ( ) ;
3110+ reinitialized_node. start ( ) . unwrap ( ) ;
3111+ assert_eq ! ( reinitialized_node. node_id( ) , expected_node_id) ;
3112+
3113+ // Balance should be persisted from the previous run.
3114+ assert_eq ! (
3115+ reinitialized_node. list_balances( ) . spendable_onchain_balance_sats,
3116+ expected_amount. to_sat( )
3117+ ) ;
3118+
3119+ wait_for_cbf_filters ( ) . await ;
3120+ reinitialized_node. sync_wallets ( ) . unwrap ( ) ;
3121+ assert_eq ! (
3122+ reinitialized_node. list_balances( ) . spendable_onchain_balance_sats,
3123+ expected_amount. to_sat( )
3124+ ) ;
3125+
3126+ reinitialized_node. stop ( ) . unwrap ( ) ;
3127+ }
3128+
3129+ #[ cfg( feature = "cbf" ) ]
3130+ #[ tokio:: test( flavor = "multi_thread" , worker_threads = 1 ) ]
3131+ async fn onchain_wallet_recovery_cbf ( ) {
3132+ let ( bitcoind, electrsd) = setup_bitcoind_and_electrsd ( ) ;
3133+ let chain_source = TestChainSource :: Cbf ( & bitcoind) ;
3134+
3135+ let original_config = random_config ( true ) ;
3136+ let original_node_entropy = original_config. node_entropy . clone ( ) ;
3137+ let original_node = setup_node ( & chain_source, original_config) ;
3138+
3139+ let premine_amount_sat = 100_000 ;
3140+
3141+ let addr_1 = original_node. onchain_payment ( ) . new_address ( ) . unwrap ( ) ;
3142+
3143+ premine_and_distribute_funds (
3144+ & bitcoind. client ,
3145+ & electrsd. client ,
3146+ vec ! [ addr_1] ,
3147+ Amount :: from_sat ( premine_amount_sat) ,
3148+ )
3149+ . await ;
3150+
3151+ wait_for_cbf_filters ( ) . await ;
3152+ original_node. sync_wallets ( ) . unwrap ( ) ;
3153+ assert_eq ! ( original_node. list_balances( ) . spendable_onchain_balance_sats, premine_amount_sat) ;
3154+
3155+ let addr_2 = original_node. onchain_payment ( ) . new_address ( ) . unwrap ( ) ;
3156+
3157+ let txid = bitcoind
3158+ . client
3159+ . send_to_address ( & addr_2, Amount :: from_sat ( premine_amount_sat) )
3160+ . unwrap ( )
3161+ . 0
3162+ . parse ( )
3163+ . unwrap ( ) ;
3164+ wait_for_tx ( & electrsd. client , txid) . await ;
3165+
3166+ generate_blocks_and_wait ( & bitcoind. client , & electrsd. client , 1 ) . await ;
3167+
3168+ wait_for_cbf_filters ( ) . await ;
3169+ original_node. sync_wallets ( ) . unwrap ( ) ;
3170+ assert_eq ! (
3171+ original_node. list_balances( ) . spendable_onchain_balance_sats,
3172+ premine_amount_sat * 2
3173+ ) ;
3174+
3175+ original_node. stop ( ) . unwrap ( ) ;
3176+ drop ( original_node) ;
3177+
3178+ // Now we start from scratch, only the seed remains the same.
3179+ let mut recovered_config = random_config ( true ) ;
3180+ recovered_config. node_entropy = original_node_entropy;
3181+ recovered_config. recovery_mode = true ;
3182+ let recovered_node = setup_node ( & chain_source, recovered_config) ;
3183+
3184+ wait_for_cbf_filters ( ) . await ;
3185+ recovered_node. sync_wallets ( ) . unwrap ( ) ;
3186+ assert_eq ! (
3187+ recovered_node. list_balances( ) . spendable_onchain_balance_sats,
3188+ premine_amount_sat * 2
3189+ ) ;
3190+
3191+ // Check we sync even when skipping some addresses.
3192+ let _addr_3 = recovered_node. onchain_payment ( ) . new_address ( ) . unwrap ( ) ;
3193+ let _addr_4 = recovered_node. onchain_payment ( ) . new_address ( ) . unwrap ( ) ;
3194+ let _addr_5 = recovered_node. onchain_payment ( ) . new_address ( ) . unwrap ( ) ;
3195+ let addr_6 = recovered_node. onchain_payment ( ) . new_address ( ) . unwrap ( ) ;
3196+
3197+ let txid = bitcoind
3198+ . client
3199+ . send_to_address ( & addr_6, Amount :: from_sat ( premine_amount_sat) )
3200+ . unwrap ( )
3201+ . 0
3202+ . parse ( )
3203+ . unwrap ( ) ;
3204+ wait_for_tx ( & electrsd. client , txid) . await ;
3205+
3206+ generate_blocks_and_wait ( & bitcoind. client , & electrsd. client , 1 ) . await ;
3207+
3208+ wait_for_cbf_filters ( ) . await ;
3209+ recovered_node. sync_wallets ( ) . unwrap ( ) ;
3210+ assert_eq ! (
3211+ recovered_node. list_balances( ) . spendable_onchain_balance_sats,
3212+ premine_amount_sat * 3
3213+ ) ;
3214+
3215+ recovered_node. stop ( ) . unwrap ( ) ;
3216+ }
3217+
3218+ #[ cfg( feature = "cbf" ) ]
3219+ #[ tokio:: test( flavor = "multi_thread" , worker_threads = 1 ) ]
3220+ async fn onchain_send_receive_cbf ( ) {
3221+ let ( bitcoind, electrsd) = setup_bitcoind_and_electrsd ( ) ;
3222+ let chain_source = TestChainSource :: Cbf ( & bitcoind) ;
3223+ let ( node_a, node_b) = setup_two_nodes ( & chain_source, false , true , false ) ;
3224+
3225+ let addr_a = node_a. onchain_payment ( ) . new_address ( ) . unwrap ( ) ;
3226+ let addr_b = node_b. onchain_payment ( ) . new_address ( ) . unwrap ( ) ;
3227+
3228+ let premine_amount_sat = 1_100_000 ;
3229+ premine_and_distribute_funds (
3230+ & bitcoind. client ,
3231+ & electrsd. client ,
3232+ vec ! [ addr_a. clone( ) , addr_b. clone( ) ] ,
3233+ Amount :: from_sat ( premine_amount_sat) ,
3234+ )
3235+ . await ;
3236+
3237+ wait_for_cbf_filters ( ) . await ;
3238+ node_a. sync_wallets ( ) . unwrap ( ) ;
3239+ node_b. sync_wallets ( ) . unwrap ( ) ;
3240+ assert_eq ! ( node_a. list_balances( ) . spendable_onchain_balance_sats, premine_amount_sat) ;
3241+ assert_eq ! ( node_b. list_balances( ) . spendable_onchain_balance_sats, premine_amount_sat) ;
3242+
3243+ // Check on-chain payment tracking after premine.
3244+ let node_a_payments = node_a. list_payments ( ) ;
3245+ let node_b_payments = node_b. list_payments ( ) ;
3246+ for payments in [ & node_a_payments, & node_b_payments] {
3247+ assert_eq ! ( payments. len( ) , 1 ) ;
3248+ }
3249+ for p in [ node_a_payments. first ( ) . unwrap ( ) , node_b_payments. first ( ) . unwrap ( ) ] {
3250+ assert_eq ! ( p. amount_msat, Some ( premine_amount_sat * 1000 ) ) ;
3251+ assert_eq ! ( p. direction, PaymentDirection :: Inbound ) ;
3252+ assert_eq ! ( p. status, PaymentStatus :: Pending ) ;
3253+ match p. kind {
3254+ PaymentKind :: Onchain { status, .. } => {
3255+ assert ! ( matches!( status, ConfirmationStatus :: Confirmed { .. } ) ) ;
3256+ } ,
3257+ _ => panic ! ( "Unexpected payment kind" ) ,
3258+ }
3259+ }
3260+
3261+ // Send from B to A.
3262+ let amount_to_send_sats = 54_321 ;
3263+ let txid =
3264+ node_b. onchain_payment ( ) . send_to_address ( & addr_a, amount_to_send_sats, None ) . unwrap ( ) ;
3265+ wait_for_tx ( & electrsd. client , txid) . await ;
3266+
3267+ // Mine the transaction so CBF can see it.
3268+ generate_blocks_and_wait ( & bitcoind. client , & electrsd. client , 6 ) . await ;
3269+ wait_for_cbf_filters ( ) . await ;
3270+
3271+ node_a. sync_wallets ( ) . unwrap ( ) ;
3272+ node_b. sync_wallets ( ) . unwrap ( ) ;
3273+
3274+ let payment_id = PaymentId ( txid. to_byte_array ( ) ) ;
3275+ let payment_a = node_a. payment ( & payment_id) . unwrap ( ) ;
3276+ match payment_a. kind {
3277+ PaymentKind :: Onchain { txid : tx, status } => {
3278+ assert_eq ! ( tx, txid) ;
3279+ assert ! ( matches!( status, ConfirmationStatus :: Confirmed { .. } ) ) ;
3280+ } ,
3281+ _ => panic ! ( "Unexpected payment kind" ) ,
3282+ }
3283+ assert ! ( payment_a. fee_paid_msat > Some ( 0 ) ) ;
3284+ assert_eq ! ( payment_a. amount_msat, Some ( amount_to_send_sats * 1000 ) ) ;
3285+
3286+ let payment_b = node_b. payment ( & payment_id) . unwrap ( ) ;
3287+ match payment_b. kind {
3288+ PaymentKind :: Onchain { txid : tx, status } => {
3289+ assert_eq ! ( tx, txid) ;
3290+ assert ! ( matches!( status, ConfirmationStatus :: Confirmed { .. } ) ) ;
3291+ } ,
3292+ _ => panic ! ( "Unexpected payment kind" ) ,
3293+ }
3294+ assert ! ( payment_b. fee_paid_msat > Some ( 0 ) ) ;
3295+ assert_eq ! ( payment_b. amount_msat, Some ( amount_to_send_sats * 1000 ) ) ;
3296+ assert_eq ! ( payment_a. fee_paid_msat, payment_b. fee_paid_msat) ;
3297+
3298+ let onchain_fee_buffer_sat = 1000 ;
3299+ let expected_node_a_balance = premine_amount_sat + amount_to_send_sats;
3300+ assert_eq ! ( node_a. list_balances( ) . spendable_onchain_balance_sats, expected_node_a_balance) ;
3301+ assert ! (
3302+ node_b. list_balances( ) . spendable_onchain_balance_sats
3303+ > premine_amount_sat - amount_to_send_sats - onchain_fee_buffer_sat
3304+ ) ;
3305+ assert ! (
3306+ node_b. list_balances( ) . spendable_onchain_balance_sats
3307+ < premine_amount_sat - amount_to_send_sats
3308+ ) ;
3309+
3310+ // Test send_all_to_address.
3311+ let addr_b2 = node_b. onchain_payment ( ) . new_address ( ) . unwrap ( ) ;
3312+ let txid = node_a. onchain_payment ( ) . send_all_to_address ( & addr_b2, false , None ) . unwrap ( ) ;
3313+ wait_for_tx ( & electrsd. client , txid) . await ;
3314+
3315+ generate_blocks_and_wait ( & bitcoind. client , & electrsd. client , 6 ) . await ;
3316+ wait_for_cbf_filters ( ) . await ;
3317+
3318+ node_a. sync_wallets ( ) . unwrap ( ) ;
3319+ node_b. sync_wallets ( ) . unwrap ( ) ;
3320+
3321+ assert_eq ! ( node_a. list_balances( ) . spendable_onchain_balance_sats, 0 ) ;
3322+ assert_eq ! ( node_a. list_balances( ) . total_onchain_balance_sats, 0 ) ;
3323+ assert ! ( node_b. list_balances( ) . spendable_onchain_balance_sats > premine_amount_sat) ;
3324+
3325+ node_a. stop ( ) . unwrap ( ) ;
3326+ node_b. stop ( ) . unwrap ( ) ;
3327+ }
0 commit comments