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<RpcBlockchain, crate::Error> {
- 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()
- }
-}