88mod common;
99
1010use common:: {
11- do_channel_full_cycle, expect_channel_pending_event, expect_channel_ready_event, expect_event,
11+ bump_fee_and_broadcast, distribute_funds_unconfirmed, do_channel_full_cycle,
12+ expect_channel_pending_event, expect_channel_ready_event, expect_event,
1213 expect_payment_claimable_event, expect_payment_received_event, expect_payment_successful_event,
1314 generate_blocks_and_wait,
1415 logging:: { init_log_logger, validate_log_entry, TestLogWriter } ,
15- open_channel, premine_and_distribute_funds, random_config , random_listening_addresses ,
16- setup_bitcoind_and_electrsd, setup_builder, setup_node, setup_two_nodes , wait_for_tx ,
17- TestChainSource , TestSyncStore ,
16+ open_channel, premine_and_distribute_funds, premine_blocks , prepare_rbf , random_config ,
17+ random_listening_addresses , setup_bitcoind_and_electrsd, setup_builder, setup_node,
18+ setup_two_nodes , wait_for_tx , TestChainSource , TestSyncStore ,
1819} ;
1920
2021use ldk_node:: config:: EsploraSyncConfig ;
@@ -35,10 +36,10 @@ use lightning_types::payment::{PaymentHash, PaymentPreimage};
3536use bitcoin:: address:: NetworkUnchecked ;
3637use bitcoin:: hashes:: sha256:: Hash as Sha256Hash ;
3738use bitcoin:: hashes:: Hash ;
38- use bitcoin:: Address ;
39- use bitcoin:: Amount ;
39+ use bitcoin:: { Address , Amount , ScriptBuf } ;
4040use log:: LevelFilter ;
4141
42+ use std:: collections:: HashSet ;
4243use std:: str:: FromStr ;
4344use std:: sync:: Arc ;
4445
@@ -670,6 +671,141 @@ fn onchain_wallet_recovery() {
670671 ) ;
671672}
672673
674+ #[ test]
675+ fn test_rbf_via_mempool ( ) {
676+ run_rbf_test ( false ) ;
677+ }
678+
679+ #[ test]
680+ fn test_rbf_via_direct_block_insertion ( ) {
681+ run_rbf_test ( true ) ;
682+ }
683+
684+ // `is_insert_block`:
685+ // - `true`: transaction is mined immediately (no mempool), testing confirmed-Tx handling.
686+ // - `false`: transaction stays in mempool until confirmation, testing unconfirmed-Tx handling.
687+ fn run_rbf_test ( is_insert_block : bool ) {
688+ let ( bitcoind, electrsd) = setup_bitcoind_and_electrsd ( ) ;
689+ let chain_source_bitcoind = TestChainSource :: BitcoindRpcSync ( & bitcoind) ;
690+ let chain_source_electrsd = TestChainSource :: Electrum ( & electrsd) ;
691+ let chain_source_esplora = TestChainSource :: Esplora ( & electrsd) ;
692+
693+ macro_rules! config_node {
694+ ( $chain_source: expr, $anchor_channels: expr) => { {
695+ let config_a = random_config( $anchor_channels) ;
696+ let node = setup_node( & $chain_source, config_a, None ) ;
697+ node
698+ } } ;
699+ }
700+ let anchor_channels = false ;
701+ let nodes = vec ! [
702+ config_node!( chain_source_electrsd, anchor_channels) ,
703+ config_node!( chain_source_bitcoind, anchor_channels) ,
704+ config_node!( chain_source_esplora, anchor_channels) ,
705+ ] ;
706+
707+ let ( bitcoind, electrs) = ( & bitcoind. client , & electrsd. client ) ;
708+ premine_blocks ( bitcoind, electrs) ;
709+
710+ // Helpers declaration before starting the test
711+ let all_addrs =
712+ nodes. iter ( ) . map ( |node| node. onchain_payment ( ) . new_address ( ) . unwrap ( ) ) . collect :: < Vec < _ > > ( ) ;
713+ let amount_sat = 2_100_000 ;
714+ let mut txid;
715+ macro_rules! distribute_funds_all_nodes {
716+ ( ) => {
717+ txid = distribute_funds_unconfirmed(
718+ bitcoind,
719+ electrs,
720+ all_addrs. clone( ) ,
721+ Amount :: from_sat( amount_sat) ,
722+ ) ;
723+ } ;
724+ }
725+ macro_rules! validate_balances {
726+ ( $expected_balance_sat: expr, $is_spendable: expr) => {
727+ let spend_balance = if $is_spendable { $expected_balance_sat } else { 0 } ;
728+ for node in & nodes {
729+ node. sync_wallets( ) . unwrap( ) ;
730+ let balances = node. list_balances( ) ;
731+ assert_eq!( balances. spendable_onchain_balance_sats, spend_balance) ;
732+ assert_eq!( balances. total_onchain_balance_sats, $expected_balance_sat) ;
733+ }
734+ } ;
735+ }
736+
737+ let scripts_buf: HashSet < ScriptBuf > =
738+ all_addrs. iter ( ) . map ( |addr| addr. script_pubkey ( ) ) . collect ( ) ;
739+ let mut tx;
740+ let mut fee_output_index;
741+
742+ // Modify the output to the nodes
743+ distribute_funds_all_nodes ! ( ) ;
744+ validate_balances ! ( amount_sat, false ) ;
745+ ( tx, fee_output_index) = prepare_rbf ( electrs, txid, & scripts_buf) ;
746+ tx. output . iter_mut ( ) . for_each ( |output| {
747+ if scripts_buf. contains ( & output. script_pubkey ) {
748+ let new_addr = bitcoind. new_address ( ) . unwrap ( ) ;
749+ output. script_pubkey = new_addr. script_pubkey ( ) ;
750+ }
751+ } ) ;
752+ bump_fee_and_broadcast ( bitcoind, electrs, tx, fee_output_index, is_insert_block) ;
753+ validate_balances ! ( 0 , is_insert_block) ;
754+
755+ // Not modifying the output scripts, but still bumping the fee.
756+ distribute_funds_all_nodes ! ( ) ;
757+ validate_balances ! ( amount_sat, false ) ;
758+ ( tx, fee_output_index) = prepare_rbf ( electrs, txid, & scripts_buf) ;
759+ bump_fee_and_broadcast ( bitcoind, electrs, tx, fee_output_index, is_insert_block) ;
760+ validate_balances ! ( amount_sat, is_insert_block) ;
761+
762+ let mut final_amount_sat = amount_sat * 2 ;
763+ let value_sat = 21_000 ;
764+
765+ // Increase the value of the nodes' outputs
766+ distribute_funds_all_nodes ! ( ) ;
767+ ( tx, fee_output_index) = prepare_rbf ( electrs, txid, & scripts_buf) ;
768+ tx. output . iter_mut ( ) . for_each ( |output| {
769+ if scripts_buf. contains ( & output. script_pubkey ) {
770+ output. value = Amount :: from_sat ( output. value . to_sat ( ) + value_sat) ;
771+ }
772+ } ) ;
773+ bump_fee_and_broadcast ( bitcoind, electrs, tx, fee_output_index, is_insert_block) ;
774+ final_amount_sat += value_sat;
775+ validate_balances ! ( final_amount_sat, is_insert_block) ;
776+
777+ // Decreases the value of the nodes' outputs
778+ distribute_funds_all_nodes ! ( ) ;
779+ final_amount_sat += amount_sat;
780+ ( tx, fee_output_index) = prepare_rbf ( electrs, txid, & scripts_buf) ;
781+ tx. output . iter_mut ( ) . for_each ( |output| {
782+ if scripts_buf. contains ( & output. script_pubkey ) {
783+ output. value = Amount :: from_sat ( output. value . to_sat ( ) - value_sat) ;
784+ }
785+ } ) ;
786+ bump_fee_and_broadcast ( bitcoind, electrs, tx, fee_output_index, is_insert_block) ;
787+ final_amount_sat -= value_sat;
788+ validate_balances ! ( final_amount_sat, is_insert_block) ;
789+
790+ if !is_insert_block {
791+ generate_blocks_and_wait ( bitcoind, electrs, 1 ) ;
792+ validate_balances ! ( final_amount_sat, true ) ;
793+ }
794+
795+ // Check if it is possible to send all funds from the node
796+ let mut txids = Vec :: new ( ) ;
797+ let addr = bitcoind. new_address ( ) . unwrap ( ) ;
798+ nodes. iter ( ) . for_each ( |node| {
799+ let txid = node. onchain_payment ( ) . send_all_to_address ( & addr, true , None ) . unwrap ( ) ;
800+ txids. push ( txid) ;
801+ } ) ;
802+ txids. iter ( ) . for_each ( |txid| {
803+ wait_for_tx ( electrs, * txid) ;
804+ } ) ;
805+ generate_blocks_and_wait ( bitcoind, electrs, 6 ) ;
806+ validate_balances ! ( 0 , true ) ;
807+ }
808+
673809#[ test]
674810fn sign_verify_msg ( ) {
675811 let ( _bitcoind, electrsd) = setup_bitcoind_and_electrsd ( ) ;
0 commit comments