@@ -29,9 +29,12 @@ use lightning_types::payment::{PaymentHash, PaymentPreimage};
2929
3030use lightning_persister:: fs_store:: FilesystemStore ;
3131
32+ use bitcoin:: hashes:: hex:: FromHex ;
3233use bitcoin:: hashes:: sha256:: Hash as Sha256 ;
3334use bitcoin:: hashes:: Hash ;
34- use bitcoin:: { Address , Amount , Network , OutPoint , Txid } ;
35+ use bitcoin:: {
36+ Address , Amount , Network , OutPoint , ScriptBuf , Sequence , Transaction , Txid , Witness ,
37+ } ;
3538
3639use electrsd:: corepc_node:: Client as BitcoindClient ;
3740use electrsd:: corepc_node:: Node as BitcoinD ;
@@ -40,7 +43,9 @@ use electrum_client::ElectrumApi;
4043
4144use rand:: distributions:: Alphanumeric ;
4245use rand:: { thread_rng, Rng } ;
46+ use serde_json:: { json, Value } ;
4347
48+ use std:: collections:: { HashMap , HashSet } ;
4449use std:: env;
4550use std:: path:: PathBuf ;
4651use std:: sync:: { Arc , RwLock } ;
@@ -470,16 +475,47 @@ where
470475pub ( crate ) fn premine_and_distribute_funds < E : ElectrumApi > (
471476 bitcoind : & BitcoindClient , electrs : & E , addrs : Vec < Address > , amount : Amount ,
472477) {
478+ premine_blocks ( bitcoind, electrs) ;
479+
480+ distribute_funds ( bitcoind, electrs, addrs, amount) ;
481+ }
482+
483+ pub ( crate ) fn premine_blocks < E : ElectrumApi > ( bitcoind : & BitcoindClient , electrs : & E ) {
473484 let _ = bitcoind. create_wallet ( "ldk_node_test" ) ;
474485 let _ = bitcoind. load_wallet ( "ldk_node_test" ) ;
475486 generate_blocks_and_wait ( bitcoind, electrs, 101 ) ;
487+ }
476488
477- for addr in addrs {
478- let txid = bitcoind. send_to_address ( & addr, amount) . unwrap ( ) . 0 . parse ( ) . unwrap ( ) ;
479- wait_for_tx ( electrs, txid) ;
489+ pub ( crate ) fn distribute_funds < E : ElectrumApi > (
490+ bitcoind : & BitcoindClient , electrs : & E , addrs : Vec < Address > , amount : Amount ,
491+ ) -> Txid {
492+ let address_txid_map = distribute_funds_unconfirmed ( bitcoind, electrs, addrs, amount) ;
493+ generate_blocks_and_wait ( bitcoind, electrs, 1 ) ;
494+
495+ address_txid_map
496+ }
497+
498+ pub ( crate ) fn distribute_funds_unconfirmed < E : ElectrumApi > (
499+ bitcoind : & BitcoindClient , electrs : & E , addrs : Vec < Address > , amount : Amount ,
500+ ) -> Txid {
501+ let mut amounts = HashMap :: < String , f64 > :: new ( ) ;
502+ for addr in & addrs {
503+ amounts. insert ( addr. to_string ( ) , amount. to_btc ( ) ) ;
480504 }
481505
482- generate_blocks_and_wait ( bitcoind, electrs, 1 ) ;
506+ let empty_account = json ! ( "" ) ;
507+ let amounts_json = json ! ( amounts) ;
508+ let txid = bitcoind
509+ . call :: < Value > ( "sendmany" , & [ empty_account, amounts_json] )
510+ . unwrap ( )
511+ . as_str ( )
512+ . unwrap ( )
513+ . parse ( )
514+ . unwrap ( ) ;
515+
516+ wait_for_tx ( electrs, txid) ;
517+
518+ txid
483519}
484520
485521pub fn open_channel (
@@ -1074,6 +1110,170 @@ pub(crate) fn do_channel_full_cycle<E: ElectrumApi>(
10741110 println ! ( "\n B stopped" ) ;
10751111}
10761112
1113+ pub ( crate ) struct MultiNodeTestSetup {
1114+ pub nodes_a : Vec < TestNode > ,
1115+ pub nodes_b : Vec < TestNode > ,
1116+ pub addrs_a : Vec < Address > ,
1117+ pub addrs_b : Vec < Address > ,
1118+ }
1119+
1120+ impl MultiNodeTestSetup {
1121+ pub ( crate ) fn new ( bitcoind : & BitcoinD , electrsd : & ElectrsD ) -> Self {
1122+ let chain_source_bitcoind = TestChainSource :: BitcoindRpcSync ( bitcoind) ;
1123+ let chain_source_electrum = TestChainSource :: Electrum ( electrsd) ;
1124+ let chain_source_esplora = TestChainSource :: Esplora ( electrsd) ;
1125+
1126+ let ( node_bitcoind_a, node_bitcoind_b) =
1127+ setup_two_nodes ( & chain_source_bitcoind, false , false , false ) ;
1128+ let ( node_electrsd_a, node_electrsd_b) =
1129+ setup_two_nodes ( & chain_source_electrum, false , false , false ) ;
1130+ let ( node_esplora_a, node_esplora_b) =
1131+ setup_two_nodes ( & chain_source_esplora, false , false , false ) ;
1132+
1133+ let nodes_a = vec ! [ node_bitcoind_a, node_electrsd_a, node_esplora_a] ;
1134+ let nodes_b = vec ! [ node_bitcoind_b, node_electrsd_b, node_esplora_b] ;
1135+
1136+ let addrs_a = nodes_a
1137+ . iter ( )
1138+ . map ( |node| node. onchain_payment ( ) . new_address ( ) . unwrap ( ) )
1139+ . collect :: < Vec < _ > > ( ) ;
1140+ let addrs_b = nodes_b
1141+ . iter ( )
1142+ . map ( |node| node. onchain_payment ( ) . new_address ( ) . unwrap ( ) )
1143+ . collect :: < Vec < _ > > ( ) ;
1144+
1145+ Self { nodes_a, nodes_b, addrs_a, addrs_b }
1146+ }
1147+
1148+ pub ( crate ) fn sync_wallets ( & self ) {
1149+ for node in & self . nodes_a {
1150+ node. sync_wallets ( ) . unwrap ( ) ;
1151+ }
1152+ for node in & self . nodes_b {
1153+ node. sync_wallets ( ) . unwrap ( ) ;
1154+ }
1155+ }
1156+
1157+ pub ( crate ) fn validate_balances (
1158+ & self , nodes : & [ TestNode ] , expected_balance : u64 , is_spendable : bool ,
1159+ ) {
1160+ let spend_balance = if is_spendable { expected_balance } else { 0 } ;
1161+ for node in nodes. iter ( ) {
1162+ assert_eq ! ( node. list_balances( ) . total_onchain_balance_sats, expected_balance) ;
1163+ assert_eq ! ( node. list_balances( ) . spendable_onchain_balance_sats, spend_balance) ;
1164+ }
1165+ }
1166+
1167+ pub ( crate ) fn setup_initial_funding < E : ElectrumApi > (
1168+ & self , bitcoind : & BitcoindClient , electrs : & E , amount : u64 ,
1169+ ) -> bitcoin:: Txid {
1170+ premine_blocks ( bitcoind, electrs) ;
1171+ self . distribute_funds ( bitcoind, electrs, amount)
1172+ }
1173+
1174+ pub ( crate ) fn distribute_funds < E : ElectrumApi > (
1175+ & self , bitcoind : & BitcoindClient , electrs : & E , amount : u64 ,
1176+ ) -> bitcoin:: Txid {
1177+ let all_addrs = self . addrs_a . iter ( ) . chain ( self . addrs_b . iter ( ) ) . cloned ( ) . collect :: < Vec < _ > > ( ) ;
1178+ distribute_funds_unconfirmed ( bitcoind, electrs, all_addrs, Amount :: from_sat ( amount) )
1179+ }
1180+
1181+ pub ( crate ) fn bump_fee_rbf < E : ElectrumApi > (
1182+ & self , bitcoind : & BitcoindClient , electrs : & E , original_tx : & mut Transaction ,
1183+ fee_output_index : usize , is_insert_block : bool ,
1184+ ) -> Txid {
1185+ let mut bump_fee_amount = original_tx. vsize ( ) as u64 ;
1186+
1187+ macro_rules! bump_fee {
1188+ ( ) => { {
1189+ let fee_output = & mut original_tx. output[ fee_output_index] ;
1190+ let new_fee_value = fee_output. value. to_sat( ) . saturating_sub( bump_fee_amount) ;
1191+ fee_output. value = Amount :: from_sat( new_fee_value) ;
1192+
1193+ // dust limit
1194+ if new_fee_value < 546 {
1195+ panic!( "Warning: Fee output approaching dust limit ({} sats)" , new_fee_value) ;
1196+ }
1197+
1198+ for input in & mut original_tx. input {
1199+ input. sequence = Sequence :: ENABLE_RBF_NO_LOCKTIME ;
1200+ input. script_sig = ScriptBuf :: new( ) ;
1201+ input. witness = Witness :: new( ) ;
1202+ }
1203+
1204+ let signed_result =
1205+ bitcoind. sign_raw_transaction_with_wallet( & original_tx) . unwrap( ) ;
1206+ assert!( signed_result. complete, "Failed to sign RBF transaction" ) ;
1207+
1208+ let tx_bytes = Vec :: <u8 >:: from_hex( & signed_result. hex) . unwrap( ) ;
1209+ let tx = bitcoin:: consensus:: encode:: deserialize:: <Transaction >( & tx_bytes) . unwrap( ) ;
1210+
1211+ tx
1212+ } } ;
1213+ }
1214+ let attempts = 3 ;
1215+ for _attempt in 0 ..attempts {
1216+ let tx = bump_fee ! ( ) ;
1217+ match bitcoind. send_raw_transaction ( & tx) {
1218+ Ok ( res) => {
1219+ // Mine a block immediately so the transaction is confirmed
1220+ // before any node identifies it as a transaction that was in the mempool.
1221+ if is_insert_block {
1222+ generate_blocks_and_wait ( bitcoind, electrs, 1 ) ;
1223+ }
1224+ let new_txid = res. 0 . parse ( ) . unwrap ( ) ;
1225+ wait_for_tx ( electrs, new_txid) ;
1226+ return new_txid;
1227+ } ,
1228+ Err ( _) => {
1229+ bump_fee_amount += bump_fee_amount * 5 ;
1230+ if original_tx. output [ fee_output_index] . value . to_sat ( ) < bump_fee_amount {
1231+ panic ! ( "Insufficient funds to increase fee" ) ;
1232+ }
1233+ } ,
1234+ }
1235+ }
1236+
1237+ panic ! ( "Failed to pump fee after {} attempts" , attempts) ;
1238+ }
1239+
1240+ pub ( crate ) fn prepare_rbf < E : ElectrumApi > (
1241+ & self , electrs : & E , original_txid : Txid ,
1242+ ) -> ( Transaction , HashSet < ScriptBuf > , HashSet < ScriptBuf > , usize ) {
1243+ let original_tx: Transaction = electrs. transaction_get ( & original_txid) . unwrap ( ) ;
1244+
1245+ let total_addresses_to_modify = & self . addrs_a . len ( ) + & self . addrs_b . len ( ) ;
1246+ if original_tx. output . len ( ) <= total_addresses_to_modify {
1247+ panic ! (
1248+ "Transaction must have more outputs ({}) than addresses to modify ({}) to allow fee pumping" ,
1249+ original_tx. output. len( ) ,
1250+ total_addresses_to_modify
1251+ ) ;
1252+ }
1253+
1254+ let scripts_a: HashSet < ScriptBuf > =
1255+ self . addrs_a . iter ( ) . map ( |addr| addr. script_pubkey ( ) ) . collect ( ) ;
1256+ let scripts_b: HashSet < ScriptBuf > =
1257+ self . addrs_b . iter ( ) . map ( |addr| addr. script_pubkey ( ) ) . collect ( ) ;
1258+
1259+ let mut fee_output_index: Option < usize > = None ;
1260+ for ( index, output) in original_tx. output . iter ( ) . enumerate ( ) {
1261+ if !scripts_a. contains ( & output. script_pubkey )
1262+ && !scripts_b. contains ( & output. script_pubkey )
1263+ {
1264+ fee_output_index = Some ( index) ;
1265+ break ;
1266+ }
1267+ }
1268+
1269+ let fee_output_index = fee_output_index. expect (
1270+ "No output available for fee pumping. Need at least one output not being modified." ,
1271+ ) ;
1272+
1273+ ( original_tx, scripts_a, scripts_b, fee_output_index)
1274+ }
1275+ }
1276+
10771277// A `KVStore` impl for testing purposes that wraps all our `KVStore`s and asserts their synchronicity.
10781278pub ( crate ) struct TestSyncStore {
10791279 serializer : RwLock < ( ) > ,
0 commit comments