@@ -20,10 +20,11 @@ use common::{
2020 bump_fee_and_broadcast, distribute_funds_unconfirmed, do_channel_full_cycle,
2121 expect_channel_pending_event, expect_channel_ready_event, expect_event,
2222 expect_payment_claimable_event, expect_payment_received_event, expect_payment_successful_event,
23- generate_blocks_and_wait, new_node, open_channel, open_channel_push_amt,
24- premine_and_distribute_funds, premine_blocks, prepare_rbf, random_config,
25- random_listening_addresses, setup_bitcoind_and_electrsd, setup_builder, setup_node,
26- setup_node_for_async_payments, setup_two_nodes, wait_for_tx, TestChainSource , TestSyncStore ,
23+ generate_block_and_insert_transactions, generate_blocks_and_wait, new_node, open_channel,
24+ open_channel_push_amt, premine_and_distribute_funds, premine_blocks, prepare_rbf,
25+ random_config, random_listening_addresses, setup_bitcoind_and_electrsd, setup_builder,
26+ setup_node, setup_node_for_async_payments, setup_two_nodes, wait_for_tx, TestChainSource ,
27+ TestSyncStore ,
2728} ;
2829use ldk_node:: config:: { AsyncPaymentsRole , EsploraSyncConfig } ;
2930use ldk_node:: liquidity:: LSPS2ServiceConfig ;
@@ -669,19 +670,24 @@ fn onchain_wallet_recovery() {
669670}
670671
671672#[ test]
672- fn test_rbf_via_mempool ( ) {
673- run_rbf_test ( false ) ;
673+ fn test_rbf_only_in_mempool ( ) {
674+ run_rbf_test ( false , false ) ;
674675}
675676
676677#[ test]
677- fn test_rbf_via_direct_block_insertion ( ) {
678- run_rbf_test ( true ) ;
678+ fn test_rbf_direct_block_insertion_rbf_tx ( ) {
679+ run_rbf_test ( true , false ) ;
680+ }
681+
682+ #[ test]
683+ fn test_rbf_direct_block_insertion_original_tx ( ) {
684+ run_rbf_test ( false , true ) ;
679685}
680686
681687// `is_insert_block`:
682688// - `true`: transaction is mined immediately (no mempool), testing confirmed-Tx handling.
683689// - `false`: transaction stays in mempool until confirmation, testing unconfirmed-Tx handling.
684- fn run_rbf_test ( is_insert_block : bool ) {
690+ fn run_rbf_test ( is_insert_block : bool , is_insertion_original_tx : bool ) {
685691 let ( bitcoind, electrsd) = setup_bitcoind_and_electrsd ( ) ;
686692 let chain_source_bitcoind = TestChainSource :: BitcoindRpcSync ( & bitcoind) ;
687693 let chain_source_electrsd = TestChainSource :: Electrum ( & electrsd) ;
@@ -724,58 +730,98 @@ fn run_rbf_test(is_insert_block: bool) {
724730 } ;
725731 }
726732
733+ macro_rules! validate_total_onchain_balance {
734+ ( $expected_balance_sat: expr) => {
735+ for node in & nodes {
736+ node. sync_wallets( ) . unwrap( ) ;
737+ let balances = node. list_balances( ) ;
738+ assert_eq!( balances. total_onchain_balance_sats, $expected_balance_sat) ;
739+ }
740+ } ;
741+ }
742+
727743 let scripts_buf: HashSet < ScriptBuf > =
728744 all_addrs. iter ( ) . map ( |addr| addr. script_pubkey ( ) ) . collect ( ) ;
729745 let mut tx;
730746 let mut fee_output_index;
731747
732- // Modify the output to the nodes
748+ let mut final_amount_sat = 0 ;
749+ let mut original_tx;
750+
751+ // Step 1: Bump fee and change output address
733752 distribute_funds_all_nodes ! ( ) ;
734753 validate_balances ! ( amount_sat, false ) ;
735754 ( tx, fee_output_index) = prepare_rbf ( electrs, txid, & scripts_buf) ;
755+ original_tx = tx. clone ( ) ;
736756 tx. output . iter_mut ( ) . for_each ( |output| {
737757 if scripts_buf. contains ( & output. script_pubkey ) {
738758 let new_addr = bitcoind. new_address ( ) . unwrap ( ) ;
739759 output. script_pubkey = new_addr. script_pubkey ( ) ;
740760 }
741761 } ) ;
742762 bump_fee_and_broadcast ( bitcoind, electrs, tx, fee_output_index, is_insert_block) ;
743- validate_balances ! ( 0 , is_insert_block) ;
763+ if is_insertion_original_tx {
764+ generate_block_and_insert_transactions ( bitcoind, electrs, & [ original_tx. clone ( ) ] ) ;
765+ }
766+ if is_insertion_original_tx {
767+ final_amount_sat += amount_sat;
768+ }
769+ validate_balances ! ( final_amount_sat, is_insert_block || is_insertion_original_tx) ;
744770
745- // Not modifying the output scripts, but still bumping the fee.
771+ // Step 2: Bump fee only
746772 distribute_funds_all_nodes ! ( ) ;
747- validate_balances ! ( amount_sat, false ) ;
773+ validate_total_onchain_balance ! ( amount_sat + final_amount_sat ) ;
748774 ( tx, fee_output_index) = prepare_rbf ( electrs, txid, & scripts_buf) ;
775+ original_tx = tx. clone ( ) ;
749776 bump_fee_and_broadcast ( bitcoind, electrs, tx, fee_output_index, is_insert_block) ;
750- validate_balances ! ( amount_sat, is_insert_block) ;
777+ if is_insertion_original_tx {
778+ generate_block_and_insert_transactions ( bitcoind, electrs, & [ original_tx. clone ( ) ] ) ;
779+ }
780+ final_amount_sat += amount_sat;
781+ validate_balances ! ( final_amount_sat, is_insert_block || is_insertion_original_tx) ;
751782
752- let mut final_amount_sat = amount_sat * 2 ;
783+ // Step 3: Increase output value
753784 let value_sat = 21_000 ;
754-
755- // Increase the value of the nodes' outputs
756785 distribute_funds_all_nodes ! ( ) ;
786+ validate_total_onchain_balance ! ( amount_sat + final_amount_sat) ;
757787 ( tx, fee_output_index) = prepare_rbf ( electrs, txid, & scripts_buf) ;
788+ original_tx = tx. clone ( ) ;
758789 tx. output . iter_mut ( ) . for_each ( |output| {
759790 if scripts_buf. contains ( & output. script_pubkey ) {
760791 output. value = Amount :: from_sat ( output. value . to_sat ( ) + value_sat) ;
761792 }
762793 } ) ;
794+ tx. output [ fee_output_index] . value -= Amount :: from_sat ( scripts_buf. len ( ) as u64 * value_sat) ;
763795 bump_fee_and_broadcast ( bitcoind, electrs, tx, fee_output_index, is_insert_block) ;
764- final_amount_sat += value_sat;
765- validate_balances ! ( final_amount_sat, is_insert_block) ;
796+ if is_insertion_original_tx {
797+ generate_block_and_insert_transactions ( bitcoind, electrs, & [ original_tx. clone ( ) ] ) ;
798+ }
799+ final_amount_sat += amount_sat;
800+ if !is_insertion_original_tx {
801+ final_amount_sat += value_sat;
802+ }
803+ validate_balances ! ( final_amount_sat, is_insert_block || is_insertion_original_tx) ;
766804
767- // Decreases the value of the nodes' outputs
805+ // Step 4: Decrease output value
768806 distribute_funds_all_nodes ! ( ) ;
769- final_amount_sat += amount_sat ;
807+ validate_total_onchain_balance ! ( amount_sat + final_amount_sat ) ;
770808 ( tx, fee_output_index) = prepare_rbf ( electrs, txid, & scripts_buf) ;
809+ original_tx = tx. clone ( ) ;
771810 tx. output . iter_mut ( ) . for_each ( |output| {
772811 if scripts_buf. contains ( & output. script_pubkey ) {
773812 output. value = Amount :: from_sat ( output. value . to_sat ( ) - value_sat) ;
774813 }
775814 } ) ;
815+ tx. output [ fee_output_index] . value += Amount :: from_sat ( scripts_buf. len ( ) as u64 * value_sat) ;
776816 bump_fee_and_broadcast ( bitcoind, electrs, tx, fee_output_index, is_insert_block) ;
777- final_amount_sat -= value_sat;
778- validate_balances ! ( final_amount_sat, is_insert_block) ;
817+ if is_insertion_original_tx {
818+ generate_block_and_insert_transactions ( bitcoind, electrs, & [ original_tx. clone ( ) ] ) ;
819+ }
820+ final_amount_sat += amount_sat;
821+ if !is_insertion_original_tx {
822+ final_amount_sat -= value_sat;
823+ }
824+ validate_balances ! ( final_amount_sat, is_insert_block || is_insertion_original_tx) ;
779825
780826 if !is_insert_block {
781827 generate_blocks_and_wait ( bitcoind, electrs, 1 ) ;
0 commit comments