Merge commit 'refs/pull/375/head' of github.com:bitcoindevkit/bdk
This commit is contained in:
		
						commit
						bab9d99a00
					
				
							
								
								
									
										41
									
								
								.github/workflows/cont_integration.yml
									
									
									
									
										vendored
									
									
								
							
							
						
						
									
										41
									
								
								.github/workflows/cont_integration.yml
									
									
									
									
										vendored
									
									
								
							| @ -77,28 +77,14 @@ jobs: | |||||||
| 
 | 
 | ||||||
|   test-blockchains: |   test-blockchains: | ||||||
|     name: Test ${{ matrix.blockchain.name }} |     name: Test ${{ matrix.blockchain.name }} | ||||||
|     runs-on: ubuntu-16.04 |     runs-on: ubuntu-20.04 | ||||||
|     strategy: |     strategy: | ||||||
|       fail-fast: false |       fail-fast: false | ||||||
|       matrix: |       matrix: | ||||||
|         blockchain: |         blockchain: | ||||||
|           - name: electrum |           - name: electrum | ||||||
|             container: bitcoindevkit/electrs:0.4.0 |  | ||||||
|             start: /root/electrs --network regtest --cookie-file $GITHUB_WORKSPACE/.bitcoin/regtest/.cookie --jsonrpc-import |  | ||||||
|           - name: esplora |  | ||||||
|             container: bitcoindevkit/esplora:0.4.0 |  | ||||||
|             start: /root/electrs --network regtest -vvv --daemon-dir $GITHUB_WORKSPACE/.bitcoin --jsonrpc-import --electrum-rpc-addr=0.0.0.0:60401 --http-addr 0.0.0.0:3002 |  | ||||||
|           - name: rpc |           - name: rpc | ||||||
|             container: bitcoindevkit/electrs:0.4.0 |           - name: esplora | ||||||
|             start: /root/electrs --network regtest --cookie-file $GITHUB_WORKSPACE/.bitcoin/regtest/.cookie --jsonrpc-import |  | ||||||
|     container: ${{ matrix.blockchain.container }} |  | ||||||
|     env: |  | ||||||
|       BDK_RPC_AUTH: COOKIEFILE |  | ||||||
|       BDK_RPC_COOKIEFILE: ${{ github.workspace }}/.bitcoin/regtest/.cookie |  | ||||||
|       BDK_RPC_URL: 127.0.0.1:18443 |  | ||||||
|       BDK_RPC_WALLET: bdk-test |  | ||||||
|       BDK_ELECTRUM_URL: tcp://127.0.0.1:60401 |  | ||||||
|       BDK_ESPLORA_URL: http://127.0.0.1:3002 |  | ||||||
|     steps: |     steps: | ||||||
|       - name: Checkout |       - name: Checkout | ||||||
|         uses: actions/checkout@v2 |         uses: actions/checkout@v2 | ||||||
| @ -107,25 +93,18 @@ jobs: | |||||||
|         with: |         with: | ||||||
|           path: | |           path: | | ||||||
|             ~/.cargo/registry |             ~/.cargo/registry | ||||||
|  |             ~/.cargo/bitcoin | ||||||
|  |             ~/.cargo/electrs | ||||||
|             ~/.cargo/git |             ~/.cargo/git | ||||||
|             target |             target | ||||||
|           key: ${{ runner.os }}-cargo-${{ github.job }}-${{ hashFiles('**/Cargo.toml','**/Cargo.lock') }} |           key: ${{ runner.os }}-cargo-${{ github.job }}-${{ hashFiles('**/Cargo.toml','**/Cargo.lock') }} | ||||||
|       - name: get pkg-config # running esplora tests seems to need this |       - name: Setup rust toolchain | ||||||
|         run: apt update && apt install -y --fix-missing pkg-config libssl-dev |         uses: actions-rs/toolchain@v1 | ||||||
|       - name: Install rustup |         with: | ||||||
|         run: curl https://sh.rustup.rs -sSf | sh -s -- -y |           toolchain: stable | ||||||
|       - name: Set default toolchain |           override: true | ||||||
|         run: $HOME/.cargo/bin/rustup default 1.53.0 # STABLE |  | ||||||
|       - name: Set profile |  | ||||||
|         run: $HOME/.cargo/bin/rustup set profile minimal |  | ||||||
|       - name: Update toolchain |  | ||||||
|         run: $HOME/.cargo/bin/rustup update |  | ||||||
|       - name: Start core |  | ||||||
|         run: ./ci/start-core.sh |  | ||||||
|       - name: start ${{ matrix.blockchain.name }} |  | ||||||
|         run: nohup ${{ matrix.blockchain.start }} & sleep 5 |  | ||||||
|       - name: Test |       - name: Test | ||||||
|         run: $HOME/.cargo/bin/cargo test --features test-${{ matrix.blockchain.name }},test-blockchains --no-default-features ${{ matrix.blockchain.name }}::bdk_blockchain_tests |         run: cargo test --features test-${{ matrix.blockchain.name }} ${{ matrix.blockchain.name }}::bdk_blockchain_tests | ||||||
| 
 | 
 | ||||||
|   check-wasm: |   check-wasm: | ||||||
|     name: Check WASM |     name: Check WASM | ||||||
|  | |||||||
							
								
								
									
										10
									
								
								Cargo.toml
									
									
									
									
									
								
							
							
						
						
									
										10
									
								
								Cargo.toml
									
									
									
									
									
								
							| @ -35,7 +35,6 @@ bitcoinconsensus = { version = "0.19.0-3", optional = true } | |||||||
| 
 | 
 | ||||||
| # Needed by bdk_blockchain_tests macro | # Needed by bdk_blockchain_tests macro | ||||||
| bitcoincore-rpc = { version = "0.13", optional = true } | bitcoincore-rpc = { version = "0.13", optional = true } | ||||||
| serial_test = { version = "0.4", optional = true } |  | ||||||
| 
 | 
 | ||||||
| # Platform-specific dependencies | # Platform-specific dependencies | ||||||
| [target.'cfg(not(target_arch = "wasm32"))'.dependencies] | [target.'cfg(not(target_arch = "wasm32"))'.dependencies] | ||||||
| @ -63,17 +62,16 @@ rpc = ["bitcoincore-rpc"] | |||||||
| 
 | 
 | ||||||
| # Debug/Test features | # Debug/Test features | ||||||
| test-blockchains = ["bitcoincore-rpc", "electrum-client"] | test-blockchains = ["bitcoincore-rpc", "electrum-client"] | ||||||
| test-electrum = ["electrum"] | test-electrum = ["electrum", "electrsd/electrs_0_8_10", "test-blockchains"] | ||||||
| test-rpc = ["rpc"] | test-rpc = ["rpc", "electrsd/electrs_0_8_10", "test-blockchains"] | ||||||
| test-esplora = ["esplora"] | test-esplora = ["esplora", "electrsd/legacy", "electrsd/esplora_a33e97e1", "test-blockchains"] | ||||||
| test-md-docs = ["electrum"] | test-md-docs = ["electrum"] | ||||||
| 
 | 
 | ||||||
| [dev-dependencies] | [dev-dependencies] | ||||||
| lazy_static = "1.4" | lazy_static = "1.4" | ||||||
| env_logger = "0.7" | env_logger = "0.7" | ||||||
| clap = "2.33" | clap = "2.33" | ||||||
| serial_test = "0.4" | electrsd = { version= "0.6", features = ["trigger", "bitcoind_0_21_1"] } | ||||||
| bitcoind = "0.10.0" |  | ||||||
| 
 | 
 | ||||||
| [[example]] | [[example]] | ||||||
| name = "address_validator" | name = "address_validator" | ||||||
|  | |||||||
							
								
								
									
										19
									
								
								README.md
									
									
									
									
									
								
							
							
						
						
									
										19
									
								
								README.md
									
									
									
									
									
								
							| @ -151,6 +151,25 @@ fn main() -> Result<(), bdk::Error> { | |||||||
| } | } | ||||||
| ``` | ``` | ||||||
| 
 | 
 | ||||||
|  | ## Testing | ||||||
|  | 
 | ||||||
|  | ### Unit testing | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | cargo test | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | ### Integration testing | ||||||
|  | 
 | ||||||
|  | Integration testing require testing features, for example: | ||||||
|  | 
 | ||||||
|  | ``` | ||||||
|  | cargo test --features test-electrum | ||||||
|  | ``` | ||||||
|  | 
 | ||||||
|  | The other options are `test-esplora` or `test-rpc`. | ||||||
|  | Note that `electrs` and `bitcoind` binaries are automatically downloaded (on mac and linux), to specify you already have installed binaries you must use `--no-default-features` and provide `BITCOIND_EXE` and `ELECTRS_EXE` as environment variables. | ||||||
|  | 
 | ||||||
| ## License | ## License | ||||||
| 
 | 
 | ||||||
| Licensed under either of | Licensed under either of | ||||||
|  | |||||||
| @ -1,71 +0,0 @@ | |||||||
| #!/bin/sh |  | ||||||
| 
 |  | ||||||
| usage() { |  | ||||||
|     cat <<'EOF' |  | ||||||
| Script for running the bdk blockchain tests for a specific blockchain by starting up the backend in docker. |  | ||||||
| 
 |  | ||||||
| Usage: ./run_blockchain_tests.sh [esplora|electrum|rpc] [test name]. |  | ||||||
| 
 |  | ||||||
| EOF |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| eprintln(){ |  | ||||||
|     echo "$@" >&2 |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| cleanup() { |  | ||||||
|     if test "$id"; then |  | ||||||
|         eprintln "cleaning up $blockchain docker container $id"; |  | ||||||
|         docker rm -fv "$id" > /dev/null; |  | ||||||
|         rm /tmp/regtest-"$id".cookie; |  | ||||||
|     fi |  | ||||||
|     trap - EXIT INT |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| # Makes sure we clean up the container at the end or if ^C |  | ||||||
| trap 'rc=$?; cleanup; exit $rc' EXIT INT |  | ||||||
| 
 |  | ||||||
| blockchain="$1" |  | ||||||
| test_name="$2" |  | ||||||
| 
 |  | ||||||
| case "$blockchain" in |  | ||||||
|     electrum) |  | ||||||
|         eprintln "starting electrs docker container" |  | ||||||
|         id="$(docker run --detach -p 127.0.0.1:18443-18444:18443-18444/tcp -p 127.0.0.1:60401:60401/tcp bitcoindevkit/electrs:0.4.0)" |  | ||||||
|         ;; |  | ||||||
|     esplora) |  | ||||||
|         eprintln "starting esplora docker container" |  | ||||||
|         id="$(docker run --detach -p 127.0.0.1:18443-18444:18443-18444/tcp -p 127.0.0.1:60401:60401/tcp -p 127.0.0.1:3002:3002/tcp bitcoindevkit/esplora:0.4.0)" |  | ||||||
|         export BDK_ESPLORA_URL=http://127.0.0.1:3002 |  | ||||||
|         ;; |  | ||||||
|     rpc) |  | ||||||
|         eprintln "starting bitcoind docker container (via electrs container)" |  | ||||||
|         id="$(docker run --detach -p 127.0.0.1:18443-18444:18443-18444/tcp -p 127.0.0.1:60401:60401/tcp bitcoindevkit/electrs:0.4.0)"       |  | ||||||
|         ;; |  | ||||||
|     *) |  | ||||||
|         usage; |  | ||||||
|         exit 1; |  | ||||||
|         ;; |  | ||||||
|     esac |  | ||||||
| 
 |  | ||||||
| # taken from https://github.com/bitcoindevkit/bitcoin-regtest-box |  | ||||||
| export BDK_RPC_AUTH=COOKIEFILE |  | ||||||
| export BDK_RPC_COOKIEFILE=/tmp/regtest-"$id".cookie |  | ||||||
| export BDK_RPC_URL=127.0.0.1:18443 |  | ||||||
| export BDK_RPC_WALLET=bdk-test |  | ||||||
| export BDK_ELECTRUM_URL=tcp://127.0.0.1:60401 |  | ||||||
| 
 |  | ||||||
| cli(){ |  | ||||||
|     docker exec -it "$id" /root/bitcoin-cli -regtest -datadir=/root/.bitcoin $@ |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| #eprintln "running getwalletinfo until bitcoind seems to be alive" |  | ||||||
| while ! cli getwalletinfo >/dev/null; do sleep 1; done |  | ||||||
| 
 |  | ||||||
| # sleep again for good measure! |  | ||||||
| sleep 1; |  | ||||||
| 
 |  | ||||||
| # copy bitcoind cookie file to /tmp |  | ||||||
| docker cp "$id":/root/.bitcoin/regtest/.cookie /tmp/regtest-"$id".cookie |  | ||||||
| 
 |  | ||||||
| cargo test --features "test-blockchains,test-$blockchain" --no-default-features "$blockchain::bdk_blockchain_tests::$test_name" |  | ||||||
| @ -169,9 +169,10 @@ impl ConfigurableBlockchain for ElectrumBlockchain { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[cfg(feature = "test-blockchains")] | #[cfg(test)] | ||||||
|  | #[cfg(feature = "test-electrum")] | ||||||
| crate::bdk_blockchain_tests! { | crate::bdk_blockchain_tests! { | ||||||
|     fn test_instance() -> ElectrumBlockchain { |     fn test_instance(test_client: &TestClient) -> ElectrumBlockchain { | ||||||
|         ElectrumBlockchain::from(Client::new(&testutils::blockchain_tests::get_electrum_url()).unwrap()) |         ElectrumBlockchain::from(Client::new(&test_client.electrsd.electrum_url).unwrap()) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -415,9 +415,10 @@ impl_error!(std::num::ParseIntError, Parsing, EsploraError); | |||||||
| impl_error!(consensus::encode::Error, BitcoinEncoding, EsploraError); | impl_error!(consensus::encode::Error, BitcoinEncoding, EsploraError); | ||||||
| impl_error!(bitcoin::hashes::hex::Error, Hex, EsploraError); | impl_error!(bitcoin::hashes::hex::Error, Hex, EsploraError); | ||||||
| 
 | 
 | ||||||
| #[cfg(feature = "test-blockchains")] | #[cfg(test)] | ||||||
|  | #[cfg(feature = "test-esplora")] | ||||||
| crate::bdk_blockchain_tests! { | crate::bdk_blockchain_tests! { | ||||||
|     fn test_instance() -> EsploraBlockchain { |     fn test_instance(test_client: &TestClient) -> EsploraBlockchain { | ||||||
|         EsploraBlockchain::new(std::env::var("BDK_ESPLORA_URL").unwrap_or("127.0.0.1:3002".into()).as_str(), None) |         EsploraBlockchain::new(&format!("http://{}",test_client.electrsd.esplora_url.as_ref().unwrap()), None) | ||||||
|     } |     } | ||||||
| } | } | ||||||
|  | |||||||
| @ -422,27 +422,14 @@ fn list_wallet_dir(client: &Client) -> Result<Vec<String>, Error> { | |||||||
|     Ok(result.wallets.into_iter().map(|n| n.name).collect()) |     Ok(result.wallets.into_iter().map(|n| n.name).collect()) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[cfg(feature = "test-blockchains")] | #[cfg(test)] | ||||||
|  | #[cfg(feature = "test-rpc")] | ||||||
| crate::bdk_blockchain_tests! { | crate::bdk_blockchain_tests! { | ||||||
| 
 | 
 | ||||||
|     fn test_instance() -> RpcBlockchain { |     fn test_instance(test_client: &TestClient) -> RpcBlockchain { | ||||||
|         let url = std::env::var("BDK_RPC_URL").unwrap_or_else(|_| "127.0.0.1:18443".to_string()); |  | ||||||
|         let url = format!("http://{}", url); |  | ||||||
| 
 |  | ||||||
|         // TODO same code in `fn get_auth` in testutils, make it public there
 |  | ||||||
|         let auth = match std::env::var("BDK_RPC_AUTH").as_ref().map(String::as_ref) { |  | ||||||
|             Ok("USER_PASS") => Auth::UserPass( |  | ||||||
|                 std::env::var("BDK_RPC_USER").unwrap(), |  | ||||||
|                 std::env::var("BDK_RPC_PASS").unwrap(), |  | ||||||
|             ), |  | ||||||
|             _ => Auth::CookieFile(std::path::PathBuf::from( |  | ||||||
|                 std::env::var("BDK_RPC_COOKIEFILE") |  | ||||||
|                     .unwrap_or_else(|_| "/home/user/.bitcoin/regtest/.cookie".to_string()), |  | ||||||
|             )), |  | ||||||
|         }; |  | ||||||
|         let config = RpcConfig { |         let config = RpcConfig { | ||||||
|             url, |             url: test_client.bitcoind.rpc_url(), | ||||||
|             auth, |             auth: Auth::CookieFile(test_client.bitcoind.params.cookie_file.clone()), | ||||||
|             network: Network::Regtest, |             network: Network::Regtest, | ||||||
|             wallet_name: format!("client-wallet-test-{:?}", std::time::SystemTime::now() ), |             wallet_name: format!("client-wallet-test-{:?}", std::time::SystemTime::now() ), | ||||||
|             skip_blocks: None, |             skip_blocks: None, | ||||||
| @ -450,227 +437,3 @@ crate::bdk_blockchain_tests! { | |||||||
|         RpcBlockchain::from_config(&config).unwrap() |         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; |  | ||||||
|     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.config.cookie_file.clone()), |  | ||||||
|             network, |  | ||||||
|             wallet_name, |  | ||||||
|             skip_blocks: None, |  | ||||||
|         }; |  | ||||||
|         RpcBlockchain::from_config(&config) |  | ||||||
|     } |  | ||||||
|     fn create_bitcoind(args: Vec<String>) -> BitcoinD { |  | ||||||
|         let exe = std::env::var("BITCOIND_EXE").unwrap(); |  | ||||||
|         bitcoind::BitcoinD::with_args(exe, args, false, bitcoind::P2P::No).unwrap() |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     const DESCRIPTOR_PUB: &'static str = "wpkh(tpubD6NzVbkrYhZ4X2yy78HWrr1M9NT8dKeWfzNiQqDdMqqa9UmmGztGGz6TaLFGsLfdft5iu32gxq1T4eMNxExNNWzVCpf9Y6JZi5TnqoC9wJq/*)"; |  | ||||||
|     const DESCRIPTOR_PRIV: &'static str = "wpkh(tprv8ZgxMBicQKsPdZxBDUcvTSMEaLwCTzTc6gmw8KBKwa3BJzWzec4g6VUbQBHJcutDH6mMEmBeVyN27H1NF3Nu8isZ1Sts4SufWyfLE6Mf1MB/*)"; |  | ||||||
| 
 |  | ||||||
|     #[test] |  | ||||||
|     fn test_rpc_wallet_setup() { |  | ||||||
|         env_logger::try_init().unwrap(); |  | ||||||
|         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.config.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".to_string()]); |  | ||||||
|         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() |  | ||||||
|     } |  | ||||||
| } |  | ||||||
|  | |||||||
| @ -383,6 +383,7 @@ impl BatchDatabase for Tree { | |||||||
| 
 | 
 | ||||||
| #[cfg(test)] | #[cfg(test)] | ||||||
| mod test { | mod test { | ||||||
|  |     use lazy_static::lazy_static; | ||||||
|     use std::sync::{Arc, Condvar, Mutex, Once}; |     use std::sync::{Arc, Condvar, Mutex, Once}; | ||||||
|     use std::time::{SystemTime, UNIX_EPOCH}; |     use std::time::{SystemTime, UNIX_EPOCH}; | ||||||
| 
 | 
 | ||||||
|  | |||||||
| @ -235,12 +235,6 @@ pub extern crate reqwest; | |||||||
| pub extern crate sled; | pub extern crate sled; | ||||||
| 
 | 
 | ||||||
| #[allow(unused_imports)] | #[allow(unused_imports)] | ||||||
| #[cfg(test)] |  | ||||||
| #[allow(unused_imports)] |  | ||||||
| #[cfg(test)] |  | ||||||
| #[macro_use] |  | ||||||
| pub extern crate serial_test; |  | ||||||
| 
 |  | ||||||
| #[macro_use] | #[macro_use] | ||||||
| pub(crate) mod error; | pub(crate) mod error; | ||||||
| pub mod blockchain; | pub mod blockchain; | ||||||
|  | |||||||
| @ -6,38 +6,49 @@ use bitcoin::{Address, Amount, Script, Transaction, Txid}; | |||||||
| pub use bitcoincore_rpc::bitcoincore_rpc_json::AddressType; | pub use bitcoincore_rpc::bitcoincore_rpc_json::AddressType; | ||||||
| pub use bitcoincore_rpc::{Auth, Client as RpcClient, RpcApi}; | pub use bitcoincore_rpc::{Auth, Client as RpcClient, RpcApi}; | ||||||
| use core::str::FromStr; | use core::str::FromStr; | ||||||
|  | use electrsd::bitcoind::BitcoinD; | ||||||
|  | use electrsd::{bitcoind, ElectrsD}; | ||||||
| pub use electrum_client::{Client as ElectrumClient, ElectrumApi}; | pub use electrum_client::{Client as ElectrumClient, ElectrumApi}; | ||||||
| #[allow(unused_imports)] | #[allow(unused_imports)] | ||||||
| use log::{debug, error, info, trace}; | use log::{debug, error, info, trace}; | ||||||
| use std::collections::HashMap; | use std::collections::HashMap; | ||||||
| use std::env; | use std::env; | ||||||
| use std::ops::Deref; | use std::ops::Deref; | ||||||
| use std::path::PathBuf; |  | ||||||
| use std::time::Duration; | use std::time::Duration; | ||||||
| 
 | 
 | ||||||
| pub struct TestClient { | pub struct TestClient { | ||||||
|     client: RpcClient, |     pub bitcoind: BitcoinD, | ||||||
|     electrum: ElectrumClient, |     pub electrsd: ElectrsD, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl TestClient { | impl TestClient { | ||||||
|     pub fn new(rpc_host_and_wallet: String, rpc_wallet_name: String) -> Self { |     pub fn new(bitcoind_exe: String, electrs_exe: String) -> Self { | ||||||
|         let client = RpcClient::new( |         debug!("launching {} and {}", &bitcoind_exe, &electrs_exe); | ||||||
|             format!("http://{}/wallet/{}", rpc_host_and_wallet, rpc_wallet_name), |         let bitcoind = BitcoinD::new(bitcoind_exe).unwrap(); | ||||||
|             get_auth(), |  | ||||||
|         ) |  | ||||||
|         .unwrap(); |  | ||||||
|         let electrum = ElectrumClient::new(&get_electrum_url()).unwrap(); |  | ||||||
| 
 | 
 | ||||||
|         TestClient { client, electrum } |         let http_enabled = cfg!(feature = "test-esplora"); | ||||||
|  | 
 | ||||||
|  |         let electrsd = ElectrsD::new(electrs_exe, &bitcoind, false, http_enabled).unwrap(); | ||||||
|  | 
 | ||||||
|  |         let node_address = bitcoind.client.get_new_address(None, None).unwrap(); | ||||||
|  |         bitcoind | ||||||
|  |             .client | ||||||
|  |             .generate_to_address(101, &node_address) | ||||||
|  |             .unwrap(); | ||||||
|  | 
 | ||||||
|  |         let mut test_client = TestClient { bitcoind, electrsd }; | ||||||
|  |         TestClient::wait_for_block(&mut test_client, 101); | ||||||
|  |         test_client | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn wait_for_tx(&mut self, txid: Txid, monitor_script: &Script) { |     fn wait_for_tx(&mut self, txid: Txid, monitor_script: &Script) { | ||||||
|         // wait for electrs to index the tx
 |         // wait for electrs to index the tx
 | ||||||
|         exponential_backoff_poll(|| { |         exponential_backoff_poll(|| { | ||||||
|  |             self.electrsd.trigger().unwrap(); | ||||||
|             trace!("wait_for_tx {}", txid); |             trace!("wait_for_tx {}", txid); | ||||||
| 
 | 
 | ||||||
|             self.electrum |             self.electrsd | ||||||
|  |                 .client | ||||||
|                 .script_get_history(monitor_script) |                 .script_get_history(monitor_script) | ||||||
|                 .unwrap() |                 .unwrap() | ||||||
|                 .iter() |                 .iter() | ||||||
| @ -46,12 +57,13 @@ impl TestClient { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn wait_for_block(&mut self, min_height: usize) { |     fn wait_for_block(&mut self, min_height: usize) { | ||||||
|         self.electrum.block_headers_subscribe().unwrap(); |         self.electrsd.client.block_headers_subscribe().unwrap(); | ||||||
| 
 | 
 | ||||||
|         loop { |         loop { | ||||||
|             let header = exponential_backoff_poll(|| { |             let header = exponential_backoff_poll(|| { | ||||||
|                 self.electrum.ping().unwrap(); |                 self.electrsd.trigger().unwrap(); | ||||||
|                 self.electrum.block_headers_pop().unwrap() |                 self.electrsd.client.ping().unwrap(); | ||||||
|  |                 self.electrsd.client.block_headers_pop().unwrap() | ||||||
|             }); |             }); | ||||||
|             if header.height >= min_height { |             if header.height >= min_height { | ||||||
|                 break; |                 break; | ||||||
| @ -96,10 +108,13 @@ impl TestClient { | |||||||
|             .unwrap(); |             .unwrap(); | ||||||
| 
 | 
 | ||||||
|         // broadcast through electrum so that it caches the tx immediately
 |         // broadcast through electrum so that it caches the tx immediately
 | ||||||
|  | 
 | ||||||
|         let txid = self |         let txid = self | ||||||
|             .electrum |             .electrsd | ||||||
|  |             .client | ||||||
|             .transaction_broadcast(&deserialize(&tx.hex).unwrap()) |             .transaction_broadcast(&deserialize(&tx.hex).unwrap()) | ||||||
|             .unwrap(); |             .unwrap(); | ||||||
|  |         debug!("broadcasted to electrum {}", txid); | ||||||
| 
 | 
 | ||||||
|         if let Some(num) = meta_tx.min_confirmations { |         if let Some(num) = meta_tx.min_confirmations { | ||||||
|             self.generate(num, None); |             self.generate(num, None); | ||||||
| @ -209,7 +224,7 @@ impl TestClient { | |||||||
|         let block_hex: String = serialize(&block).to_hex(); |         let block_hex: String = serialize(&block).to_hex(); | ||||||
|         debug!("generated block hex: {}", block_hex); |         debug!("generated block hex: {}", block_hex); | ||||||
| 
 | 
 | ||||||
|         self.electrum.block_headers_subscribe().unwrap(); |         self.electrsd.client.block_headers_subscribe().unwrap(); | ||||||
| 
 | 
 | ||||||
|         let submit_result: serde_json::Value = |         let submit_result: serde_json::Value = | ||||||
|             self.call("submitblock", &[block_hex.into()]).unwrap(); |             self.call("submitblock", &[block_hex.into()]).unwrap(); | ||||||
| @ -237,7 +252,7 @@ impl TestClient { | |||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     pub fn invalidate(&mut self, num_blocks: u64) { |     pub fn invalidate(&mut self, num_blocks: u64) { | ||||||
|         self.electrum.block_headers_subscribe().unwrap(); |         self.electrsd.client.block_headers_subscribe().unwrap(); | ||||||
| 
 | 
 | ||||||
|         let best_hash = self.get_best_block_hash().unwrap(); |         let best_hash = self.get_best_block_hash().unwrap(); | ||||||
|         let initial_height = self.get_block_info(&best_hash).unwrap().height; |         let initial_height = self.get_block_info(&best_hash).unwrap().height; | ||||||
| @ -288,16 +303,25 @@ impl Deref for TestClient { | |||||||
|     type Target = RpcClient; |     type Target = RpcClient; | ||||||
| 
 | 
 | ||||||
|     fn deref(&self) -> &Self::Target { |     fn deref(&self) -> &Self::Target { | ||||||
|         &self.client |         &self.bitcoind.client | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl Default for TestClient { | impl Default for TestClient { | ||||||
|     fn default() -> Self { |     fn default() -> Self { | ||||||
|         let rpc_host_and_port = |         let bitcoind_exe = env::var("BITCOIND_EXE") | ||||||
|             env::var("BDK_RPC_URL").unwrap_or_else(|_| "127.0.0.1:18443".to_string()); |             .ok() | ||||||
|         let wallet = env::var("BDK_RPC_WALLET").unwrap_or_else(|_| "bdk-test".to_string()); |             .or(bitcoind::downloaded_exe_path()) | ||||||
|         Self::new(rpc_host_and_port, wallet) |             .expect( | ||||||
|  |                 "you should provide env var BITCOIND_EXE or specifiy a bitcoind version feature", | ||||||
|  |             ); | ||||||
|  |         let electrs_exe = env::var("ELECTRS_EXE") | ||||||
|  |             .ok() | ||||||
|  |             .or(electrsd::downloaded_exe_path()) | ||||||
|  |             .expect( | ||||||
|  |                 "you should provide env var ELECTRS_EXE or specifiy a electrsd version feature", | ||||||
|  |             ); | ||||||
|  |         Self::new(bitcoind_exe, electrs_exe) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -317,27 +341,13 @@ where | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // TODO: we currently only support env vars, we could also parse a toml file
 |  | ||||||
| fn get_auth() -> Auth { |  | ||||||
|     match env::var("BDK_RPC_AUTH").as_ref().map(String::as_ref) { |  | ||||||
|         Ok("USER_PASS") => Auth::UserPass( |  | ||||||
|             env::var("BDK_RPC_USER").unwrap(), |  | ||||||
|             env::var("BDK_RPC_PASS").unwrap(), |  | ||||||
|         ), |  | ||||||
|         _ => Auth::CookieFile(PathBuf::from( |  | ||||||
|             env::var("BDK_RPC_COOKIEFILE") |  | ||||||
|                 .unwrap_or_else(|_| "/home/user/.bitcoin/regtest/.cookie".to_string()), |  | ||||||
|         )), |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /// This macro runs blockchain tests against a `Blockchain` implementation. It requires access to a
 | /// This macro runs blockchain tests against a `Blockchain` implementation. It requires access to a
 | ||||||
| /// Bitcoin core wallet via RPC. At the moment you have to dig into the code yourself and look at
 | /// Bitcoin core wallet via RPC. At the moment you have to dig into the code yourself and look at
 | ||||||
| /// the setup required to run the tests yourself.
 | /// the setup required to run the tests yourself.
 | ||||||
| #[macro_export] | #[macro_export] | ||||||
| macro_rules! bdk_blockchain_tests { | macro_rules! bdk_blockchain_tests { | ||||||
|     ( |     ( | ||||||
|      fn test_instance() -> $blockchain:ty $block:block) => { |      fn $_fn_name:ident ( $( $test_client:ident : &TestClient )? $(,)? ) -> $blockchain:ty $block:block) => { | ||||||
|         #[cfg(test)] |         #[cfg(test)] | ||||||
|         mod bdk_blockchain_tests { |         mod bdk_blockchain_tests { | ||||||
|             use $crate::bitcoin::Network; |             use $crate::bitcoin::Network; | ||||||
| @ -347,16 +357,17 @@ macro_rules! bdk_blockchain_tests { | |||||||
|             use $crate::types::KeychainKind; |             use $crate::types::KeychainKind; | ||||||
|             use $crate::{Wallet, FeeRate}; |             use $crate::{Wallet, FeeRate}; | ||||||
|             use $crate::testutils; |             use $crate::testutils; | ||||||
|             use $crate::serial_test::serial; |  | ||||||
| 
 | 
 | ||||||
|             use super::*; |             use super::*; | ||||||
| 
 | 
 | ||||||
|             fn get_blockchain() -> $blockchain { |             #[allow(unused_variables)] | ||||||
|  |             fn get_blockchain(test_client: &TestClient) -> $blockchain { | ||||||
|  |                 $( let $test_client = test_client; )? | ||||||
|                 $block |                 $block | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             fn get_wallet_from_descriptors(descriptors: &(String, Option<String>)) -> Wallet<$blockchain, MemoryDatabase> { |             fn get_wallet_from_descriptors(descriptors: &(String, Option<String>), test_client: &TestClient) -> Wallet<$blockchain, MemoryDatabase> { | ||||||
|                 Wallet::new(&descriptors.0.to_string(), descriptors.1.as_ref(), Network::Regtest, MemoryDatabase::new(), get_blockchain()).unwrap() |                 Wallet::new(&descriptors.0.to_string(), descriptors.1.as_ref(), Network::Regtest, MemoryDatabase::new(), get_blockchain(test_client)).unwrap() | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             fn init_single_sig() -> (Wallet<$blockchain, MemoryDatabase>, (String, Option<String>), TestClient) { |             fn init_single_sig() -> (Wallet<$blockchain, MemoryDatabase>, (String, Option<String>), TestClient) { | ||||||
| @ -367,7 +378,7 @@ macro_rules! bdk_blockchain_tests { | |||||||
|                 }; |                 }; | ||||||
| 
 | 
 | ||||||
|                 let test_client = TestClient::default(); |                 let test_client = TestClient::default(); | ||||||
|                 let wallet = get_wallet_from_descriptors(&descriptors); |                 let wallet = get_wallet_from_descriptors(&descriptors, &test_client); | ||||||
| 
 | 
 | ||||||
|                 // rpc need to call import_multi before receiving any tx, otherwise will not see tx in the mempool
 |                 // rpc need to call import_multi before receiving any tx, otherwise will not see tx in the mempool
 | ||||||
|                 #[cfg(feature = "test-rpc")] |                 #[cfg(feature = "test-rpc")] | ||||||
| @ -377,7 +388,6 @@ macro_rules! bdk_blockchain_tests { | |||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             #[test] |             #[test] | ||||||
|             #[serial] |  | ||||||
|             fn test_sync_simple() { |             fn test_sync_simple() { | ||||||
|                 let (wallet, descriptors, mut test_client) = init_single_sig(); |                 let (wallet, descriptors, mut test_client) = init_single_sig(); | ||||||
| 
 | 
 | ||||||
| @ -400,7 +410,6 @@ macro_rules! bdk_blockchain_tests { | |||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             #[test] |             #[test] | ||||||
|             #[serial] |  | ||||||
|             fn test_sync_stop_gap_20() { |             fn test_sync_stop_gap_20() { | ||||||
|                 let (wallet, descriptors, mut test_client) = init_single_sig(); |                 let (wallet, descriptors, mut test_client) = init_single_sig(); | ||||||
| 
 | 
 | ||||||
| @ -418,7 +427,6 @@ macro_rules! bdk_blockchain_tests { | |||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             #[test] |             #[test] | ||||||
|             #[serial] |  | ||||||
|             fn test_sync_before_and_after_receive() { |             fn test_sync_before_and_after_receive() { | ||||||
|                 let (wallet, descriptors, mut test_client) = init_single_sig(); |                 let (wallet, descriptors, mut test_client) = init_single_sig(); | ||||||
| 
 | 
 | ||||||
| @ -436,7 +444,6 @@ macro_rules! bdk_blockchain_tests { | |||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             #[test] |             #[test] | ||||||
|             #[serial] |  | ||||||
|             fn test_sync_multiple_outputs_same_tx() { |             fn test_sync_multiple_outputs_same_tx() { | ||||||
|                 let (wallet, descriptors, mut test_client) = init_single_sig(); |                 let (wallet, descriptors, mut test_client) = init_single_sig(); | ||||||
| 
 | 
 | ||||||
| @ -458,7 +465,6 @@ macro_rules! bdk_blockchain_tests { | |||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             #[test] |             #[test] | ||||||
|             #[serial] |  | ||||||
|             fn test_sync_receive_multi() { |             fn test_sync_receive_multi() { | ||||||
|                 let (wallet, descriptors, mut test_client) = init_single_sig(); |                 let (wallet, descriptors, mut test_client) = init_single_sig(); | ||||||
| 
 | 
 | ||||||
| @ -477,7 +483,6 @@ macro_rules! bdk_blockchain_tests { | |||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             #[test] |             #[test] | ||||||
|             #[serial] |  | ||||||
|             fn test_sync_address_reuse() { |             fn test_sync_address_reuse() { | ||||||
|                 let (wallet, descriptors, mut test_client) = init_single_sig(); |                 let (wallet, descriptors, mut test_client) = init_single_sig(); | ||||||
| 
 | 
 | ||||||
| @ -497,7 +502,6 @@ macro_rules! bdk_blockchain_tests { | |||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             #[test] |             #[test] | ||||||
|             #[serial] |  | ||||||
|             fn test_sync_receive_rbf_replaced() { |             fn test_sync_receive_rbf_replaced() { | ||||||
|                 let (wallet, descriptors, mut test_client) = init_single_sig(); |                 let (wallet, descriptors, mut test_client) = init_single_sig(); | ||||||
| 
 | 
 | ||||||
| @ -536,7 +540,6 @@ macro_rules! bdk_blockchain_tests { | |||||||
|             // doesn't work for some reason.
 |             // doesn't work for some reason.
 | ||||||
|             #[cfg(not(feature = "esplora"))] |             #[cfg(not(feature = "esplora"))] | ||||||
|             #[test] |             #[test] | ||||||
|             #[serial] |  | ||||||
|             fn test_sync_reorg_block() { |             fn test_sync_reorg_block() { | ||||||
|                 let (wallet, descriptors, mut test_client) = init_single_sig(); |                 let (wallet, descriptors, mut test_client) = init_single_sig(); | ||||||
| 
 | 
 | ||||||
| @ -567,7 +570,6 @@ macro_rules! bdk_blockchain_tests { | |||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             #[test] |             #[test] | ||||||
|             #[serial] |  | ||||||
|             fn test_sync_after_send() { |             fn test_sync_after_send() { | ||||||
|                 let (wallet, descriptors, mut test_client) = init_single_sig(); |                 let (wallet, descriptors, mut test_client) = init_single_sig(); | ||||||
|                 println!("{}", descriptors.0); |                 println!("{}", descriptors.0); | ||||||
| @ -588,7 +590,6 @@ macro_rules! bdk_blockchain_tests { | |||||||
|                 let tx = psbt.extract_tx(); |                 let tx = psbt.extract_tx(); | ||||||
|                 println!("{}", bitcoin::consensus::encode::serialize_hex(&tx)); |                 println!("{}", bitcoin::consensus::encode::serialize_hex(&tx)); | ||||||
|                 wallet.broadcast(tx).unwrap(); |                 wallet.broadcast(tx).unwrap(); | ||||||
| 
 |  | ||||||
|                 wallet.sync(noop_progress(), None).unwrap(); |                 wallet.sync(noop_progress(), None).unwrap(); | ||||||
|                 assert_eq!(wallet.get_balance().unwrap(), details.received, "incorrect balance after send"); |                 assert_eq!(wallet.get_balance().unwrap(), details.received, "incorrect balance after send"); | ||||||
| 
 | 
 | ||||||
| @ -597,7 +598,6 @@ macro_rules! bdk_blockchain_tests { | |||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             #[test] |             #[test] | ||||||
|             #[serial] |  | ||||||
|             fn test_update_confirmation_time_after_generate() { |             fn test_update_confirmation_time_after_generate() { | ||||||
|                 let (wallet, descriptors, mut test_client) = init_single_sig(); |                 let (wallet, descriptors, mut test_client) = init_single_sig(); | ||||||
|                 println!("{}", descriptors.0); |                 println!("{}", descriptors.0); | ||||||
| @ -623,9 +623,7 @@ macro_rules! bdk_blockchain_tests { | |||||||
| 
 | 
 | ||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
| 
 |  | ||||||
|             #[test] |             #[test] | ||||||
|             #[serial] |  | ||||||
|             fn test_sync_outgoing_from_scratch() { |             fn test_sync_outgoing_from_scratch() { | ||||||
|                 let (wallet, descriptors, mut test_client) = init_single_sig(); |                 let (wallet, descriptors, mut test_client) = init_single_sig(); | ||||||
|                 let node_addr = test_client.get_node_address(None); |                 let node_addr = test_client.get_node_address(None); | ||||||
| @ -648,7 +646,7 @@ macro_rules! bdk_blockchain_tests { | |||||||
|                 assert_eq!(wallet.get_balance().unwrap(), details.received, "incorrect balance after receive"); |                 assert_eq!(wallet.get_balance().unwrap(), details.received, "incorrect balance after receive"); | ||||||
| 
 | 
 | ||||||
|                 // empty wallet
 |                 // empty wallet
 | ||||||
|                 let wallet = get_wallet_from_descriptors(&descriptors); |                 let wallet = get_wallet_from_descriptors(&descriptors, &test_client); | ||||||
| 
 | 
 | ||||||
|                 #[cfg(feature = "rpc")]  // rpc cannot see mempool tx before importmulti
 |                 #[cfg(feature = "rpc")]  // rpc cannot see mempool tx before importmulti
 | ||||||
|                 test_client.generate(1, Some(node_addr)); |                 test_client.generate(1, Some(node_addr)); | ||||||
| @ -667,7 +665,6 @@ macro_rules! bdk_blockchain_tests { | |||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             #[test] |             #[test] | ||||||
|             #[serial] |  | ||||||
|             fn test_sync_long_change_chain() { |             fn test_sync_long_change_chain() { | ||||||
|                 let (wallet, descriptors, mut test_client) = init_single_sig(); |                 let (wallet, descriptors, mut test_client) = init_single_sig(); | ||||||
|                 let node_addr = test_client.get_node_address(None); |                 let node_addr = test_client.get_node_address(None); | ||||||
| @ -698,7 +695,7 @@ macro_rules! bdk_blockchain_tests { | |||||||
| 
 | 
 | ||||||
|                 // empty wallet
 |                 // empty wallet
 | ||||||
| 
 | 
 | ||||||
|                 let wallet = get_wallet_from_descriptors(&descriptors); |                 let wallet = get_wallet_from_descriptors(&descriptors, &test_client); | ||||||
| 
 | 
 | ||||||
|                 #[cfg(feature = "rpc")]  // rpc cannot see mempool tx before importmulti
 |                 #[cfg(feature = "rpc")]  // rpc cannot see mempool tx before importmulti
 | ||||||
|                 test_client.generate(1, Some(node_addr)); |                 test_client.generate(1, Some(node_addr)); | ||||||
| @ -709,7 +706,6 @@ macro_rules! bdk_blockchain_tests { | |||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             #[test] |             #[test] | ||||||
|             #[serial] |  | ||||||
|             fn test_sync_bump_fee_basic() { |             fn test_sync_bump_fee_basic() { | ||||||
|                 let (wallet, descriptors, mut test_client) = init_single_sig(); |                 let (wallet, descriptors, mut test_client) = init_single_sig(); | ||||||
|                 let node_addr = test_client.get_node_address(None); |                 let node_addr = test_client.get_node_address(None); | ||||||
| @ -745,7 +741,6 @@ macro_rules! bdk_blockchain_tests { | |||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             #[test] |             #[test] | ||||||
|             #[serial] |  | ||||||
|             fn test_sync_bump_fee_remove_change() { |             fn test_sync_bump_fee_remove_change() { | ||||||
|                 let (wallet, descriptors, mut test_client) = init_single_sig(); |                 let (wallet, descriptors, mut test_client) = init_single_sig(); | ||||||
|                 let node_addr = test_client.get_node_address(None); |                 let node_addr = test_client.get_node_address(None); | ||||||
| @ -781,7 +776,6 @@ macro_rules! bdk_blockchain_tests { | |||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             #[test] |             #[test] | ||||||
|             #[serial] |  | ||||||
|             fn test_sync_bump_fee_add_input_simple() { |             fn test_sync_bump_fee_add_input_simple() { | ||||||
|                 let (wallet, descriptors, mut test_client) = init_single_sig(); |                 let (wallet, descriptors, mut test_client) = init_single_sig(); | ||||||
|                 let node_addr = test_client.get_node_address(None); |                 let node_addr = test_client.get_node_address(None); | ||||||
| @ -815,7 +809,6 @@ macro_rules! bdk_blockchain_tests { | |||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             #[test] |             #[test] | ||||||
|             #[serial] |  | ||||||
|             fn test_sync_bump_fee_add_input_no_change() { |             fn test_sync_bump_fee_add_input_no_change() { | ||||||
|                 let (wallet, descriptors, mut test_client) = init_single_sig(); |                 let (wallet, descriptors, mut test_client) = init_single_sig(); | ||||||
|                 let node_addr = test_client.get_node_address(None); |                 let node_addr = test_client.get_node_address(None); | ||||||
| @ -852,7 +845,6 @@ macro_rules! bdk_blockchain_tests { | |||||||
|             } |             } | ||||||
| 
 | 
 | ||||||
|             #[test] |             #[test] | ||||||
|             #[serial] |  | ||||||
|             fn test_sync_receive_coinbase() { |             fn test_sync_receive_coinbase() { | ||||||
|                 let (wallet, _, mut test_client) = init_single_sig(); |                 let (wallet, _, mut test_client) = init_single_sig(); | ||||||
| 
 | 
 | ||||||
| @ -875,5 +867,10 @@ macro_rules! bdk_blockchain_tests { | |||||||
|                 assert!(wallet.get_balance().unwrap() > 0, "incorrect balance after receiving coinbase"); |                 assert!(wallet.get_balance().unwrap() > 0, "incorrect balance after receiving coinbase"); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|     } |     }; | ||||||
|  | 
 | ||||||
|  |     ( fn $fn_name:ident ($( $tt:tt )+) -> $blockchain:ty $block:block) => { | ||||||
|  |         compile_error!(concat!("Invalid arguments `", stringify!($($tt)*), "` in the blockchain tests fn.")); | ||||||
|  |         compile_error!("Only the exact `&TestClient` type is supported, **without** any leading path items."); | ||||||
|  |     }; | ||||||
| } | } | ||||||
|  | |||||||
| @ -10,6 +10,7 @@ | |||||||
| // licenses.
 | // licenses.
 | ||||||
| #![allow(missing_docs)] | #![allow(missing_docs)] | ||||||
| 
 | 
 | ||||||
|  | #[cfg(test)] | ||||||
| #[cfg(feature = "test-blockchains")] | #[cfg(feature = "test-blockchains")] | ||||||
| pub mod blockchain_tests; | pub mod blockchain_tests; | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user