From: Elias Rohrer Date: Mon, 27 Mar 2023 11:19:15 +0000 (+0200) Subject: Move test `bitcoind`/`electrsd` out of `OnceCell` X-Git-Tag: v0.0.115~50^2~1 X-Git-Url: http://git.bitcoin.ninja/index.cgi?a=commitdiff_plain;h=f75ad8021b5b46a1a7cb2b632bb9019a8d5f4eac;p=rust-lightning Move test `bitcoind`/`electrsd` out of `OnceCell` `OnceCell` doesn't call `drop`, which makes the spawned `bitcoind`/`electrsd` instances linger around after our tests have finished. To fix this, we move them out of `OnceCell` and let every test that needs them spawn their own instances. This additional let us drop the `OnceCell` dev dependency. --- diff --git a/lightning-transaction-sync/Cargo.toml b/lightning-transaction-sync/Cargo.toml index 4ad581947..a03ea1fc6 100644 --- a/lightning-transaction-sync/Cargo.toml +++ b/lightning-transaction-sync/Cargo.toml @@ -32,5 +32,4 @@ reqwest = { version = "0.11", optional = true, default-features = false, feature lightning = { version = "0.0.114", path = "../lightning", features = ["std"] } electrsd = { version = "0.22.0", features = ["legacy", "esplora_a33e97e1", "bitcoind_23_0"] } electrum-client = "0.12.0" -once_cell = "1.16.0" tokio = { version = "1.14.0", features = ["full"] } diff --git a/lightning-transaction-sync/tests/integration_tests.rs b/lightning-transaction-sync/tests/integration_tests.rs index d2f0c70a1..151f98655 100644 --- a/lightning-transaction-sync/tests/integration_tests.rs +++ b/lightning-transaction-sync/tests/integration_tests.rs @@ -12,78 +12,61 @@ use electrsd::bitcoind::bitcoincore_rpc::bitcoincore_rpc_json::AddressType; use bitcoind::bitcoincore_rpc::RpcApi; use electrum_client::ElectrumApi; -use once_cell::sync::OnceCell; - use std::env; use std::sync::Mutex; use std::time::Duration; use std::collections::{HashMap, HashSet}; -static BITCOIND: OnceCell = OnceCell::new(); -static ELECTRSD: OnceCell = OnceCell::new(); -static PREMINE: OnceCell<()> = OnceCell::new(); -static MINER_LOCK: OnceCell> = OnceCell::new(); - -fn get_bitcoind() -> &'static BitcoinD { - BITCOIND.get_or_init(|| { - let bitcoind_exe = - env::var("BITCOIND_EXE").ok().or_else(|| bitcoind::downloaded_exe_path().ok()).expect( - "you need to provide an env var BITCOIND_EXE or specify a bitcoind version feature", - ); - let mut conf = bitcoind::Conf::default(); - conf.network = "regtest"; - let bitcoind = BitcoinD::with_conf(bitcoind_exe, &conf).unwrap(); - std::thread::sleep(Duration::from_secs(1)); - bitcoind - }) -} - -fn get_electrsd() -> &'static ElectrsD { - ELECTRSD.get_or_init(|| { - let bitcoind = get_bitcoind(); - let electrs_exe = - env::var("ELECTRS_EXE").ok().or_else(electrsd::downloaded_exe_path).expect( - "you need to provide env var ELECTRS_EXE or specify an electrsd version feature", - ); - let mut conf = electrsd::Conf::default(); - conf.http_enabled = true; - conf.network = "regtest"; - let electrsd = ElectrsD::with_conf(electrs_exe, &bitcoind, &conf).unwrap(); - std::thread::sleep(Duration::from_secs(1)); - electrsd - }) +pub fn setup_bitcoind_and_electrsd() -> (BitcoinD, ElectrsD) { + let bitcoind_exe = + env::var("BITCOIND_EXE").ok().or_else(|| bitcoind::downloaded_exe_path().ok()).expect( + "you need to provide an env var BITCOIND_EXE or specify a bitcoind version feature", + ); + let mut bitcoind_conf = bitcoind::Conf::default(); + bitcoind_conf.network = "regtest"; + let bitcoind = BitcoinD::with_conf(bitcoind_exe, &bitcoind_conf).unwrap(); + + let electrs_exe = env::var("ELECTRS_EXE") + .ok() + .or_else(electrsd::downloaded_exe_path) + .expect("you need to provide env var ELECTRS_EXE or specify an electrsd version feature"); + let mut electrsd_conf = electrsd::Conf::default(); + electrsd_conf.http_enabled = true; + electrsd_conf.network = "regtest"; + let electrsd = ElectrsD::with_conf(electrs_exe, &bitcoind, &electrsd_conf).unwrap(); + (bitcoind, electrsd) } -fn generate_blocks_and_wait(num: usize) { - let miner_lock = MINER_LOCK.get_or_init(|| Mutex::new(())); - let _miner = miner_lock.lock().unwrap(); - let cur_height = get_bitcoind().client.get_block_count().expect("failed to get current block height"); - let address = get_bitcoind().client.get_new_address(Some("test"), Some(AddressType::Legacy)).expect("failed to get new address"); +pub fn generate_blocks_and_wait(bitcoind: &BitcoinD, electrsd: &ElectrsD, num: usize) { + let cur_height = bitcoind.client.get_block_count().expect("failed to get current block height"); + let address = bitcoind + .client + .get_new_address(Some("test"), Some(AddressType::Legacy)) + .expect("failed to get new address"); // TODO: expect this Result once the WouldBlock issue is resolved upstream. - let _block_hashes_res = get_bitcoind().client.generate_to_address(num as u64, &address); - wait_for_block(cur_height as usize + num); + let _block_hashes_res = bitcoind.client.generate_to_address(num as u64, &address); + wait_for_block(electrsd, cur_height as usize + num); } -fn wait_for_block(min_height: usize) { - let mut header = match get_electrsd().client.block_headers_subscribe() { +pub fn wait_for_block(electrsd: &ElectrsD, min_height: usize) { + let mut header = match electrsd.client.block_headers_subscribe() { Ok(header) => header, Err(_) => { // While subscribing should succeed the first time around, we ran into some cases where // it didn't. Since we can't proceed without subscribing, we try again after a delay // and panic if it still fails. std::thread::sleep(Duration::from_secs(1)); - get_electrsd().client.block_headers_subscribe().expect("failed to subscribe to block headers") + electrsd.client.block_headers_subscribe().expect("failed to subscribe to block headers") } }; - loop { if header.height >= min_height { break; } header = exponential_backoff_poll(|| { - get_electrsd().trigger().expect("failed to trigger electrsd"); - get_electrsd().client.ping().expect("failed to ping electrsd"); - get_electrsd().client.block_headers_pop().expect("failed to pop block header") + electrsd.trigger().expect("failed to trigger electrsd"); + electrsd.client.ping().expect("failed to ping electrsd"); + electrsd.client.block_headers_pop().expect("failed to pop block header") }); } } @@ -109,12 +92,6 @@ where } } -fn premine() { - PREMINE.get_or_init(|| { - generate_blocks_and_wait(101); - }); -} - #[derive(Debug)] enum TestConfirmableEvent { Confirmed(Txid, BlockHash, u32), @@ -182,27 +159,25 @@ impl Logger for TestLogger { #[test] #[cfg(feature = "esplora-blocking")] fn test_esplora_syncs() { - premine(); + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + generate_blocks_and_wait(&bitcoind, &electrsd, 101); let mut logger = TestLogger {}; - let esplora_url = format!("http://{}", get_electrsd().esplora_url.as_ref().unwrap()); + let esplora_url = format!("http://{}", electrsd.esplora_url.as_ref().unwrap()); let tx_sync = EsploraSyncClient::new(esplora_url, &mut logger); let confirmable = TestConfirmable::new(); // Check we pick up on new best blocks - let expected_height = 0u32; - assert_eq!(confirmable.best_block.lock().unwrap().1, expected_height); + assert_eq!(confirmable.best_block.lock().unwrap().1, 0); tx_sync.sync(vec![&confirmable]).unwrap(); - - let expected_height = get_bitcoind().client.get_block_count().unwrap() as u32; - assert_eq!(confirmable.best_block.lock().unwrap().1, expected_height); + assert_eq!(confirmable.best_block.lock().unwrap().1, 102); let events = std::mem::take(&mut *confirmable.events.lock().unwrap()); assert_eq!(events.len(), 1); // Check registered confirmed transactions are marked confirmed - let new_address = get_bitcoind().client.get_new_address(Some("test"), Some(AddressType::Legacy)).unwrap(); - let txid = get_bitcoind().client.send_to_address(&new_address, Amount::from_sat(5000), None, None, None, None, None, None).unwrap(); + let new_address = bitcoind.client.get_new_address(Some("test"), Some(AddressType::Legacy)).unwrap(); + let txid = bitcoind.client.send_to_address(&new_address, Amount::from_sat(5000), None, None, None, None, None, None).unwrap(); tx_sync.register_tx(&txid, &new_address.script_pubkey()); tx_sync.sync(vec![&confirmable]).unwrap(); @@ -212,7 +187,7 @@ fn test_esplora_syncs() { assert!(confirmable.confirmed_txs.lock().unwrap().is_empty()); assert!(confirmable.unconfirmed_txs.lock().unwrap().is_empty()); - generate_blocks_and_wait(1); + generate_blocks_and_wait(&bitcoind, &electrsd, 1); tx_sync.sync(vec![&confirmable]).unwrap(); let events = std::mem::take(&mut *confirmable.events.lock().unwrap()); @@ -221,19 +196,19 @@ fn test_esplora_syncs() { assert!(confirmable.unconfirmed_txs.lock().unwrap().is_empty()); // Check previously confirmed transactions are marked unconfirmed when they are reorged. - let best_block_hash = get_bitcoind().client.get_best_block_hash().unwrap(); - get_bitcoind().client.invalidate_block(&best_block_hash).unwrap(); + let best_block_hash = bitcoind.client.get_best_block_hash().unwrap(); + bitcoind.client.invalidate_block(&best_block_hash).unwrap(); // We're getting back to the previous height with a new tip, but best block shouldn't change. - generate_blocks_and_wait(1); - assert_ne!(get_bitcoind().client.get_best_block_hash().unwrap(), best_block_hash); + generate_blocks_and_wait(&bitcoind, &electrsd, 1); + assert_ne!(bitcoind.client.get_best_block_hash().unwrap(), best_block_hash); tx_sync.sync(vec![&confirmable]).unwrap(); let events = std::mem::take(&mut *confirmable.events.lock().unwrap()); assert_eq!(events.len(), 0); // Now we're surpassing previous height, getting new tip. - generate_blocks_and_wait(1); - assert_ne!(get_bitcoind().client.get_best_block_hash().unwrap(), best_block_hash); + generate_blocks_and_wait(&bitcoind, &electrsd, 1); + assert_ne!(bitcoind.client.get_best_block_hash().unwrap(), best_block_hash); tx_sync.sync(vec![&confirmable]).unwrap(); // Transaction still confirmed but under new tip. @@ -267,27 +242,25 @@ fn test_esplora_syncs() { #[tokio::test] #[cfg(feature = "esplora-async")] async fn test_esplora_syncs() { - premine(); + let (bitcoind, electrsd) = setup_bitcoind_and_electrsd(); + generate_blocks_and_wait(&bitcoind, &electrsd, 101); let mut logger = TestLogger {}; - let esplora_url = format!("http://{}", get_electrsd().esplora_url.as_ref().unwrap()); + let esplora_url = format!("http://{}", electrsd.esplora_url.as_ref().unwrap()); let tx_sync = EsploraSyncClient::new(esplora_url, &mut logger); let confirmable = TestConfirmable::new(); // Check we pick up on new best blocks - let expected_height = 0u32; - assert_eq!(confirmable.best_block.lock().unwrap().1, expected_height); + assert_eq!(confirmable.best_block.lock().unwrap().1, 0); tx_sync.sync(vec![&confirmable]).await.unwrap(); - - let expected_height = get_bitcoind().client.get_block_count().unwrap() as u32; - assert_eq!(confirmable.best_block.lock().unwrap().1, expected_height); + assert_eq!(confirmable.best_block.lock().unwrap().1, 102); let events = std::mem::take(&mut *confirmable.events.lock().unwrap()); assert_eq!(events.len(), 1); // Check registered confirmed transactions are marked confirmed - let new_address = get_bitcoind().client.get_new_address(Some("test"), Some(AddressType::Legacy)).unwrap(); - let txid = get_bitcoind().client.send_to_address(&new_address, Amount::from_sat(5000), None, None, None, None, None, None).unwrap(); + let new_address = bitcoind.client.get_new_address(Some("test"), Some(AddressType::Legacy)).unwrap(); + let txid = bitcoind.client.send_to_address(&new_address, Amount::from_sat(5000), None, None, None, None, None, None).unwrap(); tx_sync.register_tx(&txid, &new_address.script_pubkey()); tx_sync.sync(vec![&confirmable]).await.unwrap(); @@ -297,7 +270,7 @@ async fn test_esplora_syncs() { assert!(confirmable.confirmed_txs.lock().unwrap().is_empty()); assert!(confirmable.unconfirmed_txs.lock().unwrap().is_empty()); - generate_blocks_and_wait(1); + generate_blocks_and_wait(&bitcoind, &electrsd, 1); tx_sync.sync(vec![&confirmable]).await.unwrap(); let events = std::mem::take(&mut *confirmable.events.lock().unwrap()); @@ -306,19 +279,19 @@ async fn test_esplora_syncs() { assert!(confirmable.unconfirmed_txs.lock().unwrap().is_empty()); // Check previously confirmed transactions are marked unconfirmed when they are reorged. - let best_block_hash = get_bitcoind().client.get_best_block_hash().unwrap(); - get_bitcoind().client.invalidate_block(&best_block_hash).unwrap(); + let best_block_hash = bitcoind.client.get_best_block_hash().unwrap(); + bitcoind.client.invalidate_block(&best_block_hash).unwrap(); // We're getting back to the previous height with a new tip, but best block shouldn't change. - generate_blocks_and_wait(1); - assert_ne!(get_bitcoind().client.get_best_block_hash().unwrap(), best_block_hash); + generate_blocks_and_wait(&bitcoind, &electrsd, 1); + assert_ne!(bitcoind.client.get_best_block_hash().unwrap(), best_block_hash); tx_sync.sync(vec![&confirmable]).await.unwrap(); let events = std::mem::take(&mut *confirmable.events.lock().unwrap()); assert_eq!(events.len(), 0); // Now we're surpassing previous height, getting new tip. - generate_blocks_and_wait(1); - assert_ne!(get_bitcoind().client.get_best_block_hash().unwrap(), best_block_hash); + generate_blocks_and_wait(&bitcoind, &electrsd, 1); + assert_ne!(bitcoind.client.get_best_block_hash().unwrap(), best_block_hash); tx_sync.sync(vec![&confirmable]).await.unwrap(); // Transaction still confirmed but under new tip.