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