diff --git a/Cargo.toml b/Cargo.toml index c89f6f95..af9dc597 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -70,7 +70,7 @@ lazy_static = "1.4" env_logger = "0.7" clap = "2.33" bitcoind = "0.11.0" -electrsd = "0.3.0" +electrsd = { version="0.3.0", features = ["trigger"] } [[example]] name = "address_validator" diff --git a/src/blockchain/rpc.rs b/src/blockchain/rpc.rs index 63664c68..0165313c 100644 --- a/src/blockchain/rpc.rs +++ b/src/blockchain/rpc.rs @@ -434,229 +434,3 @@ crate::bdk_blockchain_tests! { RpcBlockchain::from_config(&config).unwrap() } } - -#[cfg(feature = "test-rpc")] -#[cfg(test)] -mod test { - use super::{RpcBlockchain, RpcConfig}; - use crate::bitcoin::consensus::deserialize; - use crate::bitcoin::{Address, Amount, Network, Transaction}; - use crate::blockchain::rpc::wallet_name_from_descriptor; - use crate::blockchain::{noop_progress, Blockchain, Capability, ConfigurableBlockchain}; - use crate::database::MemoryDatabase; - use crate::wallet::AddressIndex; - use crate::Wallet; - use bitcoin::secp256k1::Secp256k1; - use bitcoin::Txid; - use bitcoincore_rpc::json::CreateRawTransactionInput; - use bitcoincore_rpc::RawTx; - use bitcoincore_rpc::{Auth, RpcApi}; - use bitcoind::{BitcoinD, Conf}; - use std::collections::HashMap; - - fn create_rpc( - bitcoind: &BitcoinD, - desc: &str, - network: Network, - ) -> Result { - let secp = Secp256k1::new(); - let wallet_name = wallet_name_from_descriptor(desc, None, network, &secp).unwrap(); - - let config = RpcConfig { - url: bitcoind.rpc_url(), - auth: Auth::CookieFile(bitcoind.params.cookie_file.clone()), - network, - wallet_name, - skip_blocks: None, - }; - RpcBlockchain::from_config(&config) - } - fn create_bitcoind(args: Vec<&str>) -> BitcoinD { - let exe = std::env::var("BITCOIND_EXE").unwrap(); - let mut conf = Conf::default(); - conf.args.extend(args); - bitcoind::BitcoinD::with_conf(exe, &conf).unwrap() - } - - const DESCRIPTOR_PUB: &'static str = "wpkh(tpubD6NzVbkrYhZ4X2yy78HWrr1M9NT8dKeWfzNiQqDdMqqa9UmmGztGGz6TaLFGsLfdft5iu32gxq1T4eMNxExNNWzVCpf9Y6JZi5TnqoC9wJq/*)"; - const DESCRIPTOR_PRIV: &'static str = "wpkh(tprv8ZgxMBicQKsPdZxBDUcvTSMEaLwCTzTc6gmw8KBKwa3BJzWzec4g6VUbQBHJcutDH6mMEmBeVyN27H1NF3Nu8isZ1Sts4SufWyfLE6Mf1MB/*)"; - - #[test] - fn test_rpc_wallet_setup() { - let _ = env_logger::try_init(); - let bitcoind = create_bitcoind(vec![]); - let node_address = bitcoind.client.get_new_address(None, None).unwrap(); - let blockchain = create_rpc(&bitcoind, DESCRIPTOR_PUB, Network::Regtest).unwrap(); - let db = MemoryDatabase::new(); - let wallet = Wallet::new(DESCRIPTOR_PRIV, None, Network::Regtest, db, blockchain).unwrap(); - - wallet.sync(noop_progress(), None).unwrap(); - generate(&bitcoind, 101); - wallet.sync(noop_progress(), None).unwrap(); - let address = wallet.get_address(AddressIndex::New).unwrap(); - let expected_address = "bcrt1q8dyvgt4vhr8ald4xuwewcxhdjha9a5k78wxm5t"; - assert_eq!(expected_address, address.to_string()); - send_to_address(&bitcoind, &address, 100_000); - wallet.sync(noop_progress(), None).unwrap(); - assert_eq!(wallet.get_balance().unwrap(), 100_000); - - let mut builder = wallet.build_tx(); - builder.add_recipient(node_address.script_pubkey(), 50_000); - let (mut psbt, details) = builder.finish().unwrap(); - let finalized = wallet.sign(&mut psbt, Default::default()).unwrap(); - assert!(finalized, "Cannot finalize transaction"); - let tx = psbt.extract_tx(); - wallet.broadcast(tx).unwrap(); - wallet.sync(noop_progress(), None).unwrap(); - assert_eq!( - wallet.get_balance().unwrap(), - 100_000 - 50_000 - details.fee.unwrap_or(0) - ); - drop(wallet); - - // test skip_blocks - generate(&bitcoind, 5); - let config = RpcConfig { - url: bitcoind.rpc_url(), - auth: Auth::CookieFile(bitcoind.params.cookie_file.clone()), - network: Network::Regtest, - wallet_name: "another-name".to_string(), - skip_blocks: Some(103), - }; - let blockchain_skip = RpcBlockchain::from_config(&config).unwrap(); - let db = MemoryDatabase::new(); - let wallet_skip = - Wallet::new(DESCRIPTOR_PRIV, None, Network::Regtest, db, blockchain_skip).unwrap(); - wallet_skip.sync(noop_progress(), None).unwrap(); - send_to_address(&bitcoind, &address, 100_000); - wallet_skip.sync(noop_progress(), None).unwrap(); - assert_eq!(wallet_skip.get_balance().unwrap(), 100_000); - } - - #[test] - fn test_rpc_from_config() { - let bitcoind = create_bitcoind(vec![]); - let blockchain = create_rpc(&bitcoind, DESCRIPTOR_PUB, Network::Regtest); - assert!(blockchain.is_ok()); - let blockchain = create_rpc(&bitcoind, DESCRIPTOR_PUB, Network::Testnet); - assert!(blockchain.is_err(), "wrong network doesn't error"); - } - - #[test] - fn test_rpc_capabilities_get_tx() { - let bitcoind = create_bitcoind(vec![]); - let rpc = create_rpc(&bitcoind, DESCRIPTOR_PUB, Network::Regtest).unwrap(); - let capabilities = rpc.get_capabilities(); - assert!(capabilities.contains(&Capability::FullHistory) && capabilities.len() == 1); - let bitcoind_indexed = create_bitcoind(vec!["-txindex"]); - let rpc_indexed = create_rpc(&bitcoind_indexed, DESCRIPTOR_PUB, Network::Regtest).unwrap(); - assert_eq!(rpc_indexed.get_capabilities().len(), 3); - let address = generate(&bitcoind_indexed, 101); - let txid = send_to_address(&bitcoind_indexed, &address, 100_000); - assert!(rpc_indexed.get_tx(&txid).unwrap().is_some()); - assert!(rpc.get_tx(&txid).is_err()); - } - - #[test] - fn test_rpc_estimate_fee_get_height() { - let bitcoind = create_bitcoind(vec![]); - let rpc = create_rpc(&bitcoind, DESCRIPTOR_PUB, Network::Regtest).unwrap(); - let result = rpc.estimate_fee(2); - assert!(result.is_err()); - let address = generate(&bitcoind, 100); - // create enough tx so that core give some fee estimation - for _ in 0..15 { - let _ = bitcoind.client.generate_to_address(1, &address).unwrap(); - for _ in 0..2 { - send_to_address(&bitcoind, &address, 100_000); - } - } - let result = rpc.estimate_fee(2); - assert!(result.is_ok()); - assert_eq!(rpc.get_height().unwrap(), 115); - } - - #[test] - fn test_rpc_node_synced_height() { - let bitcoind = create_bitcoind(vec![]); - let rpc = create_rpc(&bitcoind, DESCRIPTOR_PUB, Network::Regtest).unwrap(); - let synced_height = rpc.get_node_synced_height().unwrap(); - - assert_eq!(synced_height, 0); - rpc.set_node_synced_height(1).unwrap(); - - let synced_height = rpc.get_node_synced_height().unwrap(); - assert_eq!(synced_height, 1); - } - - #[test] - fn test_rpc_broadcast() { - let bitcoind = create_bitcoind(vec![]); - let rpc = create_rpc(&bitcoind, DESCRIPTOR_PUB, Network::Regtest).unwrap(); - let address = generate(&bitcoind, 101); - let utxo = bitcoind - .client - .list_unspent(None, None, None, None, None) - .unwrap(); - let input = CreateRawTransactionInput { - txid: utxo[0].txid, - vout: utxo[0].vout, - sequence: None, - }; - - let out: HashMap<_, _> = vec![( - address.to_string(), - utxo[0].amount - Amount::from_sat(100_000), - )] - .into_iter() - .collect(); - let tx = bitcoind - .client - .create_raw_transaction(&[input], &out, None, None) - .unwrap(); - let signed_tx = bitcoind - .client - .sign_raw_transaction_with_wallet(tx.raw_hex(), None, None) - .unwrap(); - let parsed_tx: Transaction = deserialize(&signed_tx.hex).unwrap(); - rpc.broadcast(&parsed_tx).unwrap(); - assert!(bitcoind - .client - .get_raw_mempool() - .unwrap() - .contains(&tx.txid())); - } - - #[test] - fn test_rpc_wallet_name() { - let secp = Secp256k1::new(); - let name = - wallet_name_from_descriptor(DESCRIPTOR_PUB, None, Network::Regtest, &secp).unwrap(); - assert_eq!("tmg7aqay", name); - } - - fn generate(bitcoind: &BitcoinD, blocks: u64) -> Address { - let address = bitcoind.client.get_new_address(None, None).unwrap(); - bitcoind - .client - .generate_to_address(blocks, &address) - .unwrap(); - address - } - - fn send_to_address(bitcoind: &BitcoinD, address: &Address, amount: u64) -> Txid { - bitcoind - .client - .send_to_address( - &address, - Amount::from_sat(amount), - None, - None, - None, - None, - None, - None, - ) - .unwrap() - } -} diff --git a/src/database/keyvalue.rs b/src/database/keyvalue.rs index ecf9f4d7..9978497d 100644 --- a/src/database/keyvalue.rs +++ b/src/database/keyvalue.rs @@ -383,9 +383,9 @@ impl BatchDatabase for Tree { #[cfg(test)] mod test { + use lazy_static::lazy_static; use std::sync::{Arc, Condvar, Mutex, Once}; use std::time::{SystemTime, UNIX_EPOCH}; - use lazy_static::lazy_static; use sled::{Db, Tree}; diff --git a/src/lib.rs b/src/lib.rs index b5548bae..2e261368 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -234,6 +234,7 @@ pub extern crate reqwest; #[cfg(feature = "key-value-db")] pub extern crate sled; +#[allow(unused_imports)] #[macro_use] pub(crate) mod error; pub mod blockchain; diff --git a/src/testutils/blockchain_tests.rs b/src/testutils/blockchain_tests.rs index 041e1a16..588e0e65 100644 --- a/src/testutils/blockchain_tests.rs +++ b/src/testutils/blockchain_tests.rs @@ -41,6 +41,7 @@ impl TestClient { fn wait_for_tx(&mut self, txid: Txid, monitor_script: &Script) { // wait for electrs to index the tx exponential_backoff_poll(|| { + self.electrsd.trigger().unwrap(); trace!("wait_for_tx {}", txid); self.electrsd @@ -57,6 +58,7 @@ impl TestClient { loop { let header = exponential_backoff_poll(|| { + self.electrsd.trigger().unwrap(); self.electrsd.client.ping().unwrap(); self.electrsd.client.block_headers_pop().unwrap() });