]> Untitled Git - bdk/commitdiff
Roll blockchain tests proc macro into normal macro
authorLLFourn <lloyd.fourn@gmail.com>
Sun, 16 May 2021 05:07:55 +0000 (15:07 +1000)
committerLLFourn <lloyd.fourn@gmail.com>
Tue, 18 May 2021 10:02:33 +0000 (20:02 +1000)
This means one less crate in the repo. Had to do a Default on TestClient
to satisfy clippy.

Cargo.toml
src/blockchain/electrum.rs
src/lib.rs
testutils-macros/Cargo.toml [deleted file]
testutils-macros/src/lib.rs [deleted file]
testutils/src/blockchain_tests.rs [new file with mode: 0644]
testutils/src/lib.rs

index 687e016c4436060cb1d025de0d9dce6e4d99febb..52176e5dadf1e418ec04e70af47c8cb3ae9e0649 100644 (file)
@@ -54,13 +54,11 @@ all-keys = ["keys-bip39"]
 keys-bip39 = ["tiny-bip39"]
 
 # Debug/Test features
-debug-proc-macros = ["bdk-macros/debug", "bdk-testutils-macros/debug"]
 test-electrum = ["electrum"]
 test-md-docs = ["electrum"]
 
 [dev-dependencies]
-bdk-testutils = "0.4"
-bdk-testutils-macros = "0.6"
+bdk-testutils = { path = "./testutils" }
 serial_test = "0.4"
 lazy_static = "1.4"
 env_logger = "0.7"
@@ -79,7 +77,7 @@ path = "examples/compiler.rs"
 required-features = ["compiler"]
 
 [workspace]
-members = ["macros", "testutils", "testutils-macros"]
+members = ["macros", "testutils"]
 
 # Generate docs with nightly to add the "features required" badge
 # https://stackoverflow.com/questions/61417452/how-to-get-a-feature-requirement-tag-in-the-documentation-generated-by-cargo-do
index 926155a320ce144fe6faa152ef5b7ec16fec6881..2e1033077c0bf314f39a01fb941993be34693f82 100644 (file)
@@ -45,13 +45,6 @@ use crate::FeeRate;
 /// See the [`blockchain::electrum`](crate::blockchain::electrum) module for a usage example.
 pub struct ElectrumBlockchain(Client);
 
-#[cfg(test)]
-#[cfg(feature = "test-electrum")]
-#[bdk_blockchain_tests(crate)]
-fn local_electrs() -> ElectrumBlockchain {
-    ElectrumBlockchain::from(Client::new(&testutils::get_electrum_url()).unwrap())
-}
-
 impl std::convert::From<Client> for ElectrumBlockchain {
     fn from(client: Client) -> Self {
         ElectrumBlockchain(client)
@@ -175,3 +168,11 @@ impl ConfigurableBlockchain for ElectrumBlockchain {
         )?))
     }
 }
+
+#[cfg(all(feature = "test-electrum", test))]
+testutils::bdk_blockchain_tests! {
+    bdk => crate,
+    fn test_instance() -> ElectrumBlockchain {
+        ElectrumBlockchain::from(Client::new(&testutils::get_electrum_url()).unwrap())
+    }
+}
index 0e7f8287b8a95770f58a2130b03e3d6c2fa25f01..a4670b5c52ad20d367569da1c0ffe716a42817eb 100644 (file)
@@ -234,8 +234,6 @@ pub extern crate sled;
 extern crate testutils;
 #[allow(unused_imports)]
 #[cfg(test)]
-#[macro_use]
-extern crate testutils_macros;
 #[allow(unused_imports)]
 #[cfg(test)]
 #[macro_use]
diff --git a/testutils-macros/Cargo.toml b/testutils-macros/Cargo.toml
deleted file mode 100644 (file)
index f78b7f9..0000000
+++ /dev/null
@@ -1,25 +0,0 @@
-[package]
-name = "bdk-testutils-macros"
-version = "0.6.0"
-authors = ["Alekos Filini <alekos.filini@gmail.com>"]
-edition = "2018"
-homepage = "https://bitcoindevkit.org"
-repository = "https://github.com/bitcoindevkit/bdk"
-documentation = "https://docs.rs/bdk-testutils-macros"
-description = "Supporting testing macros for `bdk`"
-keywords = ["bdk"]
-license = "MIT OR Apache-2.0"
-
-[lib]
-proc-macro = true
-name = "testutils_macros"
-
-# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
-
-[dependencies]
-syn = { version = "1.0", features = ["parsing", "full"] }
-proc-macro2 = "1.0"
-quote = "1.0"
-
-[features]
-debug = ["syn/extra-traits"]
diff --git a/testutils-macros/src/lib.rs b/testutils-macros/src/lib.rs
deleted file mode 100644 (file)
index db01e1e..0000000
+++ /dev/null
@@ -1,553 +0,0 @@
-// Bitcoin Dev Kit
-// Written in 2020 by Alekos Filini <alekos.filini@gmail.com>
-//
-// Copyright (c) 2020-2021 Bitcoin Dev Kit Developers
-//
-// This file is licensed under the Apache License, Version 2.0 <LICENSE-APACHE
-// or http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your option.
-// You may not use this file except in accordance with one or both of these
-// licenses.
-
-#[macro_use]
-extern crate quote;
-
-use proc_macro::TokenStream;
-
-use syn::spanned::Spanned;
-use syn::{parse, parse2, Ident, ReturnType};
-
-#[proc_macro_attribute]
-pub fn bdk_blockchain_tests(attr: TokenStream, item: TokenStream) -> TokenStream {
-    let root_ident = if !attr.is_empty() {
-        match parse::<syn::ExprPath>(attr) {
-            Ok(parsed) => parsed,
-            Err(e) => {
-                let error_string = e.to_string();
-                return (quote! {
-                    compile_error!("Invalid crate path: {:?}", #error_string)
-                })
-                .into();
-            }
-        }
-    } else {
-        parse2::<syn::ExprPath>(quote! { bdk }).unwrap()
-    };
-
-    match parse::<syn::ItemFn>(item) {
-        Err(_) => (quote! {
-            compile_error!("#[bdk_blockchain_tests] can only be used on `fn`s")
-        })
-        .into(),
-        Ok(parsed) => {
-            let parsed_sig_ident = parsed.sig.ident.clone();
-            let mod_name = Ident::new(
-                &format!("generated_tests_{}", parsed_sig_ident.to_string()),
-                parsed.span(),
-            );
-
-            let return_type = match parsed.sig.output {
-                ReturnType::Type(_, ref t) => t.clone(),
-                ReturnType::Default => {
-                    return (quote! {
-                        compile_error!("The tagged function must return a type that impl `Blockchain`")
-                    }).into();
-                }
-            };
-
-            let output = quote! {
-
-            #parsed
-
-            mod #mod_name {
-                use bitcoin::Network;
-
-                use miniscript::Descriptor;
-
-                use testutils::{TestClient, serial};
-
-                use #root_ident::blockchain::{Blockchain, noop_progress};
-                use #root_ident::descriptor::ExtendedDescriptor;
-                use #root_ident::database::MemoryDatabase;
-                use #root_ident::types::KeychainKind;
-                use #root_ident::{Wallet, TxBuilder, FeeRate};
-                use #root_ident::wallet::AddressIndex::New;
-
-                use super::*;
-
-                fn get_blockchain() -> #return_type {
-                    #parsed_sig_ident()
-                }
-
-                fn get_wallet_from_descriptors(descriptors: &(String, Option<String>)) -> Wallet<#return_type, MemoryDatabase> {
-                    Wallet::new(&descriptors.0.to_string(), descriptors.1.as_ref(), Network::Regtest, MemoryDatabase::new(), get_blockchain()).unwrap()
-                }
-
-                fn init_single_sig() -> (Wallet<#return_type, MemoryDatabase>, (String, Option<String>), TestClient) {
-                    let descriptors = testutils! {
-                        @descriptors ( "wpkh(Alice)" ) ( "wpkh(Alice)" ) ( @keys ( "Alice" => (@generate_xprv "/44'/0'/0'/0/*", "/44'/0'/0'/1/*") ) )
-                    };
-
-                    let test_client = TestClient::new();
-                    let wallet = get_wallet_from_descriptors(&descriptors);
-
-                    (wallet, descriptors, test_client)
-                }
-
-                #[test]
-                #[serial]
-                fn test_sync_simple() {
-                    let (wallet, descriptors, mut test_client) = init_single_sig();
-
-                    let tx = testutils! {
-                        @tx ( (@external descriptors, 0) => 50_000 )
-                    };
-                    println!("{:?}", tx);
-                    let txid = test_client.receive(tx);
-
-                    wallet.sync(noop_progress(), None).unwrap();
-
-                    assert_eq!(wallet.get_balance().unwrap(), 50_000);
-                    assert_eq!(wallet.list_unspent().unwrap()[0].keychain, KeychainKind::External);
-
-                    let list_tx_item = &wallet.list_transactions(false).unwrap()[0];
-                    assert_eq!(list_tx_item.txid, txid);
-                    assert_eq!(list_tx_item.received, 50_000);
-                    assert_eq!(list_tx_item.sent, 0);
-                    assert_eq!(list_tx_item.height, None);
-                }
-
-                #[test]
-                #[serial]
-                fn test_sync_stop_gap_20() {
-                    let (wallet, descriptors, mut test_client) = init_single_sig();
-
-                    test_client.receive(testutils! {
-                        @tx ( (@external descriptors, 5) => 50_000 )
-                    });
-                    test_client.receive(testutils! {
-                        @tx ( (@external descriptors, 25) => 50_000 )
-                    });
-
-                    wallet.sync(noop_progress(), None).unwrap();
-
-                    assert_eq!(wallet.get_balance().unwrap(), 100_000);
-                    assert_eq!(wallet.list_transactions(false).unwrap().len(), 2);
-                }
-
-                #[test]
-                #[serial]
-                fn test_sync_before_and_after_receive() {
-                    let (wallet, descriptors, mut test_client) = init_single_sig();
-
-                    wallet.sync(noop_progress(), None).unwrap();
-                    assert_eq!(wallet.get_balance().unwrap(), 0);
-
-                    test_client.receive(testutils! {
-                        @tx ( (@external descriptors, 0) => 50_000 )
-                    });
-
-                    wallet.sync(noop_progress(), None).unwrap();
-
-                    assert_eq!(wallet.get_balance().unwrap(), 50_000);
-                    assert_eq!(wallet.list_transactions(false).unwrap().len(), 1);
-                }
-
-                #[test]
-                #[serial]
-                fn test_sync_multiple_outputs_same_tx() {
-                    let (wallet, descriptors, mut test_client) = init_single_sig();
-
-                    let txid = test_client.receive(testutils! {
-                        @tx ( (@external descriptors, 0) => 50_000, (@external descriptors, 1) => 25_000, (@external descriptors, 5) => 30_000 )
-                    });
-
-                    wallet.sync(noop_progress(), None).unwrap();
-
-                    assert_eq!(wallet.get_balance().unwrap(), 105_000);
-                    assert_eq!(wallet.list_transactions(false).unwrap().len(), 1);
-                    assert_eq!(wallet.list_unspent().unwrap().len(), 3);
-
-                    let list_tx_item = &wallet.list_transactions(false).unwrap()[0];
-                    assert_eq!(list_tx_item.txid, txid);
-                    assert_eq!(list_tx_item.received, 105_000);
-                    assert_eq!(list_tx_item.sent, 0);
-                    assert_eq!(list_tx_item.height, None);
-                }
-
-                #[test]
-                #[serial]
-                fn test_sync_receive_multi() {
-                    let (wallet, descriptors, mut test_client) = init_single_sig();
-
-                    test_client.receive(testutils! {
-                        @tx ( (@external descriptors, 0) => 50_000 )
-                    });
-                    test_client.receive(testutils! {
-                        @tx ( (@external descriptors, 5) => 25_000 )
-                    });
-
-                    wallet.sync(noop_progress(), None).unwrap();
-
-                    assert_eq!(wallet.get_balance().unwrap(), 75_000);
-                    assert_eq!(wallet.list_transactions(false).unwrap().len(), 2);
-                    assert_eq!(wallet.list_unspent().unwrap().len(), 2);
-                }
-
-                #[test]
-                #[serial]
-                fn test_sync_address_reuse() {
-                    let (wallet, descriptors, mut test_client) = init_single_sig();
-
-                    test_client.receive(testutils! {
-                        @tx ( (@external descriptors, 0) => 50_000 )
-                    });
-
-                    wallet.sync(noop_progress(), None).unwrap();
-                    assert_eq!(wallet.get_balance().unwrap(), 50_000);
-
-                    test_client.receive(testutils! {
-                        @tx ( (@external descriptors, 0) => 25_000 )
-                    });
-
-                    wallet.sync(noop_progress(), None).unwrap();
-                    assert_eq!(wallet.get_balance().unwrap(), 75_000);
-                }
-
-                #[test]
-                #[serial]
-                fn test_sync_receive_rbf_replaced() {
-                    let (wallet, descriptors, mut test_client) = init_single_sig();
-
-                    let txid = test_client.receive(testutils! {
-                        @tx ( (@external descriptors, 0) => 50_000 ) ( @replaceable true )
-                    });
-
-                    wallet.sync(noop_progress(), None).unwrap();
-
-                    assert_eq!(wallet.get_balance().unwrap(), 50_000);
-                    assert_eq!(wallet.list_transactions(false).unwrap().len(), 1);
-                    assert_eq!(wallet.list_unspent().unwrap().len(), 1);
-
-                    let list_tx_item = &wallet.list_transactions(false).unwrap()[0];
-                    assert_eq!(list_tx_item.txid, txid);
-                    assert_eq!(list_tx_item.received, 50_000);
-                    assert_eq!(list_tx_item.sent, 0);
-                    assert_eq!(list_tx_item.height, None);
-
-                    let new_txid = test_client.bump_fee(&txid);
-
-                    wallet.sync(noop_progress(), None).unwrap();
-
-                    assert_eq!(wallet.get_balance().unwrap(), 50_000);
-                    assert_eq!(wallet.list_transactions(false).unwrap().len(), 1);
-                    assert_eq!(wallet.list_unspent().unwrap().len(), 1);
-
-                    let list_tx_item = &wallet.list_transactions(false).unwrap()[0];
-                    assert_eq!(list_tx_item.txid, new_txid);
-                    assert_eq!(list_tx_item.received, 50_000);
-                    assert_eq!(list_tx_item.sent, 0);
-                    assert_eq!(list_tx_item.height, None);
-                }
-
-                #[test]
-                #[serial]
-                fn test_sync_reorg_block() {
-                    let (wallet, descriptors, mut test_client) = init_single_sig();
-
-                    let txid = test_client.receive(testutils! {
-                        @tx ( (@external descriptors, 0) => 50_000 ) ( @confirmations 1 ) ( @replaceable true )
-                    });
-
-                    wallet.sync(noop_progress(), None).unwrap();
-
-                    assert_eq!(wallet.get_balance().unwrap(), 50_000);
-                    assert_eq!(wallet.list_transactions(false).unwrap().len(), 1);
-                    assert_eq!(wallet.list_unspent().unwrap().len(), 1);
-
-                    let list_tx_item = &wallet.list_transactions(false).unwrap()[0];
-                    assert_eq!(list_tx_item.txid, txid);
-                    assert!(list_tx_item.height.is_some());
-
-                    // Invalidate 1 block
-                    test_client.invalidate(1);
-
-                    wallet.sync(noop_progress(), None).unwrap();
-
-                    assert_eq!(wallet.get_balance().unwrap(), 50_000);
-
-                    let list_tx_item = &wallet.list_transactions(false).unwrap()[0];
-                    assert_eq!(list_tx_item.txid, txid);
-                    assert_eq!(list_tx_item.height, None);
-                }
-
-                #[test]
-                #[serial]
-                fn test_sync_after_send() {
-                    let (wallet, descriptors, mut test_client) = init_single_sig();
-                    println!("{}", descriptors.0);
-                    let node_addr = test_client.get_node_address(None);
-
-                    test_client.receive(testutils! {
-                        @tx ( (@external descriptors, 0) => 50_000 )
-                    });
-
-                    wallet.sync(noop_progress(), None).unwrap();
-                    assert_eq!(wallet.get_balance().unwrap(), 50_000);
-
-                    let mut builder = wallet.build_tx();
-                    builder.add_recipient(node_addr.script_pubkey(), 25_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();
-                    println!("{}", bitcoin::consensus::encode::serialize_hex(&tx));
-                    wallet.broadcast(tx).unwrap();
-
-                    wallet.sync(noop_progress(), None).unwrap();
-                    assert_eq!(wallet.get_balance().unwrap(), details.received);
-
-                    assert_eq!(wallet.list_transactions(false).unwrap().len(), 2);
-                    assert_eq!(wallet.list_unspent().unwrap().len(), 1);
-                }
-
-                #[test]
-                #[serial]
-                fn test_sync_outgoing_from_scratch() {
-                    let (wallet, descriptors, mut test_client) = init_single_sig();
-                    let node_addr = test_client.get_node_address(None);
-
-                    let received_txid = test_client.receive(testutils! {
-                        @tx ( (@external descriptors, 0) => 50_000 )
-                    });
-
-                    wallet.sync(noop_progress(), None).unwrap();
-                    assert_eq!(wallet.get_balance().unwrap(), 50_000);
-
-                    let mut builder = wallet.build_tx();
-                    builder.add_recipient(node_addr.script_pubkey(), 25_000);
-                    let (mut psbt, details) = builder.finish().unwrap();
-                    let finalized = wallet.sign(&mut psbt, Default::default()).unwrap();
-                    assert!(finalized, "Cannot finalize transaction");
-                    let sent_txid = wallet.broadcast(psbt.extract_tx()).unwrap();
-
-                    wallet.sync(noop_progress(), None).unwrap();
-                    assert_eq!(wallet.get_balance().unwrap(), details.received);
-
-                    // empty wallet
-                    let wallet = get_wallet_from_descriptors(&descriptors);
-                    wallet.sync(noop_progress(), None).unwrap();
-
-                    let tx_map = wallet.list_transactions(false).unwrap().into_iter().map(|tx| (tx.txid, tx)).collect::<std::collections::HashMap<_, _>>();
-
-                    let received = tx_map.get(&received_txid).unwrap();
-                    assert_eq!(received.received, 50_000);
-                    assert_eq!(received.sent, 0);
-
-                    let sent = tx_map.get(&sent_txid).unwrap();
-                    assert_eq!(sent.received, details.received);
-                    assert_eq!(sent.sent, details.sent);
-                    assert_eq!(sent.fees, details.fees);
-                }
-
-                #[test]
-                #[serial]
-                fn test_sync_long_change_chain() {
-                    let (wallet, descriptors, mut test_client) = init_single_sig();
-                    let node_addr = test_client.get_node_address(None);
-
-                    test_client.receive(testutils! {
-                        @tx ( (@external descriptors, 0) => 50_000 )
-                    });
-
-                    wallet.sync(noop_progress(), None).unwrap();
-                    assert_eq!(wallet.get_balance().unwrap(), 50_000);
-
-                    let mut total_sent = 0;
-                    for _ in 0..5 {
-                        let mut builder = wallet.build_tx();
-                        builder.add_recipient(node_addr.script_pubkey(), 5_000);
-                        let (mut psbt, details) = builder.finish().unwrap();
-                        let finalized = wallet.sign(&mut psbt, Default::default()).unwrap();
-                        assert!(finalized, "Cannot finalize transaction");
-                        wallet.broadcast(psbt.extract_tx()).unwrap();
-
-                        wallet.sync(noop_progress(), None).unwrap();
-
-                        total_sent += 5_000 + details.fees;
-                    }
-
-                    wallet.sync(noop_progress(), None).unwrap();
-                    assert_eq!(wallet.get_balance().unwrap(), 50_000 - total_sent);
-
-                    // empty wallet
-                    let wallet = get_wallet_from_descriptors(&descriptors);
-                    wallet.sync(noop_progress(), None).unwrap();
-                    assert_eq!(wallet.get_balance().unwrap(), 50_000 - total_sent);
-                }
-
-                #[test]
-                #[serial]
-                fn test_sync_bump_fee() {
-                    let (wallet, descriptors, mut test_client) = init_single_sig();
-                    let node_addr = test_client.get_node_address(None);
-
-                    test_client.receive(testutils! {
-                        @tx ( (@external descriptors, 0) => 50_000 ) (@confirmations 1)
-                    });
-
-                    wallet.sync(noop_progress(), None).unwrap();
-                    assert_eq!(wallet.get_balance().unwrap(), 50_000);
-
-                    let mut builder = wallet.build_tx();
-                    builder.add_recipient(node_addr.script_pubkey().clone(), 5_000).enable_rbf();
-                    let (mut psbt, details) = builder.finish().unwrap();
-                    let finalized = wallet.sign(&mut psbt, Default::default()).unwrap();
-                    assert!(finalized, "Cannot finalize transaction");
-                    wallet.broadcast(psbt.extract_tx()).unwrap();
-                    wallet.sync(noop_progress(), None).unwrap();
-                    assert_eq!(wallet.get_balance().unwrap(), 50_000 - details.fees - 5_000);
-                    assert_eq!(wallet.get_balance().unwrap(), details.received);
-
-                    let mut builder = wallet.build_fee_bump(details.txid).unwrap();
-                    builder.fee_rate(FeeRate::from_sat_per_vb(2.1));
-                    let (mut new_psbt, new_details) = builder.finish().unwrap();
-                    let finalized = wallet.sign(&mut new_psbt, Default::default()).unwrap();
-                    assert!(finalized, "Cannot finalize transaction");
-                    wallet.broadcast(new_psbt.extract_tx()).unwrap();
-                    wallet.sync(noop_progress(), None).unwrap();
-                    assert_eq!(wallet.get_balance().unwrap(), 50_000 - new_details.fees - 5_000);
-                    assert_eq!(wallet.get_balance().unwrap(), new_details.received);
-
-                    assert!(new_details.fees > details.fees);
-                }
-
-                #[test]
-                #[serial]
-                fn test_sync_bump_fee_remove_change() {
-                    let (wallet, descriptors, mut test_client) = init_single_sig();
-                    let node_addr = test_client.get_node_address(None);
-
-                    test_client.receive(testutils! {
-                        @tx ( (@external descriptors, 0) => 50_000 ) (@confirmations 1)
-                    });
-
-                    wallet.sync(noop_progress(), None).unwrap();
-                    assert_eq!(wallet.get_balance().unwrap(), 50_000);
-
-                    let mut builder = wallet.build_tx();
-                    builder.add_recipient(node_addr.script_pubkey().clone(), 49_000).enable_rbf();
-                    let (mut psbt, details) = builder.finish().unwrap();
-                    let finalized = wallet.sign(&mut psbt, Default::default()).unwrap();
-                    assert!(finalized, "Cannot finalize transaction");
-                    wallet.broadcast(psbt.extract_tx()).unwrap();
-                    wallet.sync(noop_progress(), None).unwrap();
-                    assert_eq!(wallet.get_balance().unwrap(), 1_000 - details.fees);
-                    assert_eq!(wallet.get_balance().unwrap(), details.received);
-
-                    let mut builder = wallet.build_fee_bump(details.txid).unwrap();
-                    builder.fee_rate(FeeRate::from_sat_per_vb(5.0));
-                    let (mut new_psbt, new_details) = builder.finish().unwrap();
-                    let finalized = wallet.sign(&mut new_psbt, Default::default()).unwrap();
-                    assert!(finalized, "Cannot finalize transaction");
-                    wallet.broadcast(new_psbt.extract_tx()).unwrap();
-                    wallet.sync(noop_progress(), None).unwrap();
-                    assert_eq!(wallet.get_balance().unwrap(), 0);
-                    assert_eq!(new_details.received, 0);
-
-                    assert!(new_details.fees > details.fees);
-                }
-
-                #[test]
-                #[serial]
-                fn test_sync_bump_fee_add_input() {
-                    let (wallet, descriptors, mut test_client) = init_single_sig();
-                    let node_addr = test_client.get_node_address(None);
-
-                    test_client.receive(testutils! {
-                        @tx ( (@external descriptors, 0) => 50_000, (@external descriptors, 1) => 25_000 ) (@confirmations 1)
-                    });
-
-                    wallet.sync(noop_progress(), None).unwrap();
-                    assert_eq!(wallet.get_balance().unwrap(), 75_000);
-
-                    let mut builder = wallet.build_tx();
-                    builder.add_recipient(node_addr.script_pubkey().clone(), 49_000).enable_rbf();
-                    let (mut psbt, details) = builder.finish().unwrap();
-                    let finalized = wallet.sign(&mut psbt, Default::default()).unwrap();
-                    assert!(finalized, "Cannot finalize transaction");
-                    wallet.broadcast(psbt.extract_tx()).unwrap();
-                    wallet.sync(noop_progress(), None).unwrap();
-                    assert_eq!(wallet.get_balance().unwrap(), 26_000 - details.fees);
-                    assert_eq!(details.received, 1_000 - details.fees);
-
-                    let mut builder = wallet.build_fee_bump(details.txid).unwrap();
-                    builder.fee_rate(FeeRate::from_sat_per_vb(10.0));
-                    let (mut new_psbt, new_details) = builder.finish().unwrap();
-                    let finalized = wallet.sign(&mut new_psbt, Default::default()).unwrap();
-                    assert!(finalized, "Cannot finalize transaction");
-                    wallet.broadcast(new_psbt.extract_tx()).unwrap();
-                    wallet.sync(noop_progress(), None).unwrap();
-                    assert_eq!(new_details.sent, 75_000);
-                    assert_eq!(wallet.get_balance().unwrap(), new_details.received);
-                }
-
-                #[test]
-                #[serial]
-                fn test_sync_bump_fee_add_input_no_change() {
-                    let (wallet, descriptors, mut test_client) = init_single_sig();
-                    let node_addr = test_client.get_node_address(None);
-
-                    test_client.receive(testutils! {
-                        @tx ( (@external descriptors, 0) => 50_000, (@external descriptors, 1) => 25_000 ) (@confirmations 1)
-                    });
-
-                    wallet.sync(noop_progress(), None).unwrap();
-                    assert_eq!(wallet.get_balance().unwrap(), 75_000);
-
-                    let mut builder = wallet.build_tx();
-                    builder.add_recipient(node_addr.script_pubkey().clone(), 49_000).enable_rbf();
-                    let (mut psbt, details) = builder.finish().unwrap();
-                    let finalized = wallet.sign(&mut psbt, Default::default()).unwrap();
-                    assert!(finalized, "Cannot finalize transaction");
-                    wallet.broadcast(psbt.extract_tx()).unwrap();
-                    wallet.sync(noop_progress(), None).unwrap();
-                    assert_eq!(wallet.get_balance().unwrap(), 26_000 - details.fees);
-                    assert_eq!(details.received, 1_000 - details.fees);
-
-                    let mut builder = wallet.build_fee_bump(details.txid).unwrap();
-                    builder.fee_rate(FeeRate::from_sat_per_vb(123.0));
-                    let (mut new_psbt, new_details) = builder.finish().unwrap();
-                    println!("{:#?}", new_details);
-
-                    let finalized = wallet.sign(&mut new_psbt, Default::default()).unwrap();
-                    assert!(finalized, "Cannot finalize transaction");
-                    wallet.broadcast(new_psbt.extract_tx()).unwrap();
-                    wallet.sync(noop_progress(), None).unwrap();
-                    assert_eq!(new_details.sent, 75_000);
-                    assert_eq!(wallet.get_balance().unwrap(), 0);
-                    assert_eq!(new_details.received, 0);
-                }
-
-                #[test]
-                #[serial]
-                fn test_sync_receive_coinbase() {
-                    let (wallet, descriptors, mut test_client) = init_single_sig();
-                    let wallet_addr = wallet.get_address(New).unwrap();
-
-                    wallet.sync(noop_progress(), None).unwrap();
-                    assert_eq!(wallet.get_balance().unwrap(), 0);
-
-                    test_client.generate(1, Some(wallet_addr));
-
-                    wallet.sync(noop_progress(), None).unwrap();
-                    assert!(wallet.get_balance().unwrap() > 0);
-                }
-            }
-
-                        };
-
-            output.into()
-        }
-    }
-}
diff --git a/testutils/src/blockchain_tests.rs b/testutils/src/blockchain_tests.rs
new file mode 100644 (file)
index 0000000..95ebcc4
--- /dev/null
@@ -0,0 +1,491 @@
+/// 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
+/// the setup required to run the tests yourself.
+#[macro_export]
+macro_rules! bdk_blockchain_tests {
+    (bdk => $bdk:ident,
+     fn test_instance() -> $blockchain:ty $block:block) => {
+        mod bdk_blockchain_tests {
+            use $bdk::bitcoin::Network;
+            use $bdk::miniscript::Descriptor;
+            use $crate::{TestClient, serial};
+            use $bdk::blockchain::{Blockchain, noop_progress};
+            use $bdk::descriptor::ExtendedDescriptor;
+            use $bdk::database::MemoryDatabase;
+            use $bdk::types::KeychainKind;
+            use $bdk::{Wallet, TxBuilder, FeeRate};
+            use $bdk::wallet::AddressIndex::New;
+
+            use super::*;
+
+            fn get_blockchain() -> $blockchain {
+                $block
+            }
+
+            fn get_wallet_from_descriptors(descriptors: &(String, Option<String>)) -> Wallet<$blockchain, MemoryDatabase> {
+                Wallet::new(&descriptors.0.to_string(), descriptors.1.as_ref(), Network::Regtest, MemoryDatabase::new(), get_blockchain()).unwrap()
+            }
+
+            fn init_single_sig() -> (Wallet<$blockchain, MemoryDatabase>, (String, Option<String>), TestClient) {
+                let descriptors = testutils! {
+                    @descriptors ( "wpkh(Alice)" ) ( "wpkh(Alice)" ) ( @keys ( "Alice" => (@generate_xprv "/44'/0'/0'/0/*", "/44'/0'/0'/1/*") ) )
+                };
+
+                let test_client = TestClient::default();
+                let wallet = get_wallet_from_descriptors(&descriptors);
+
+                (wallet, descriptors, test_client)
+            }
+
+            #[test]
+            #[serial]
+            fn test_sync_simple() {
+                let (wallet, descriptors, mut test_client) = init_single_sig();
+
+                let tx = testutils! {
+                    @tx ( (@external descriptors, 0) => 50_000 )
+                };
+                println!("{:?}", tx);
+                let txid = test_client.receive(tx);
+
+                wallet.sync(noop_progress(), None).unwrap();
+
+                assert_eq!(wallet.get_balance().unwrap(), 50_000);
+                assert_eq!(wallet.list_unspent().unwrap()[0].keychain, KeychainKind::External);
+
+                let list_tx_item = &wallet.list_transactions(false).unwrap()[0];
+                assert_eq!(list_tx_item.txid, txid);
+                assert_eq!(list_tx_item.received, 50_000);
+                assert_eq!(list_tx_item.sent, 0);
+                assert_eq!(list_tx_item.height, None);
+            }
+
+            #[test]
+            #[serial]
+            fn test_sync_stop_gap_20() {
+                let (wallet, descriptors, mut test_client) = init_single_sig();
+
+                test_client.receive(testutils! {
+                    @tx ( (@external descriptors, 5) => 50_000 )
+                });
+                test_client.receive(testutils! {
+                    @tx ( (@external descriptors, 25) => 50_000 )
+                });
+
+                wallet.sync(noop_progress(), None).unwrap();
+
+                assert_eq!(wallet.get_balance().unwrap(), 100_000);
+                assert_eq!(wallet.list_transactions(false).unwrap().len(), 2);
+            }
+
+            #[test]
+            #[serial]
+            fn test_sync_before_and_after_receive() {
+                let (wallet, descriptors, mut test_client) = init_single_sig();
+
+                wallet.sync(noop_progress(), None).unwrap();
+                assert_eq!(wallet.get_balance().unwrap(), 0);
+
+                test_client.receive(testutils! {
+                    @tx ( (@external descriptors, 0) => 50_000 )
+                });
+
+                wallet.sync(noop_progress(), None).unwrap();
+
+                assert_eq!(wallet.get_balance().unwrap(), 50_000);
+                assert_eq!(wallet.list_transactions(false).unwrap().len(), 1);
+            }
+
+            #[test]
+            #[serial]
+            fn test_sync_multiple_outputs_same_tx() {
+                let (wallet, descriptors, mut test_client) = init_single_sig();
+
+                let txid = test_client.receive(testutils! {
+                    @tx ( (@external descriptors, 0) => 50_000, (@external descriptors, 1) => 25_000, (@external descriptors, 5) => 30_000 )
+                });
+
+                wallet.sync(noop_progress(), None).unwrap();
+
+                assert_eq!(wallet.get_balance().unwrap(), 105_000);
+                assert_eq!(wallet.list_transactions(false).unwrap().len(), 1);
+                assert_eq!(wallet.list_unspent().unwrap().len(), 3);
+
+                let list_tx_item = &wallet.list_transactions(false).unwrap()[0];
+                assert_eq!(list_tx_item.txid, txid);
+                assert_eq!(list_tx_item.received, 105_000);
+                assert_eq!(list_tx_item.sent, 0);
+                assert_eq!(list_tx_item.height, None);
+            }
+
+            #[test]
+            #[serial]
+            fn test_sync_receive_multi() {
+                let (wallet, descriptors, mut test_client) = init_single_sig();
+
+                test_client.receive(testutils! {
+                    @tx ( (@external descriptors, 0) => 50_000 )
+                });
+                test_client.receive(testutils! {
+                    @tx ( (@external descriptors, 5) => 25_000 )
+                });
+
+                wallet.sync(noop_progress(), None).unwrap();
+
+                assert_eq!(wallet.get_balance().unwrap(), 75_000);
+                assert_eq!(wallet.list_transactions(false).unwrap().len(), 2);
+                assert_eq!(wallet.list_unspent().unwrap().len(), 2);
+            }
+
+            #[test]
+            #[serial]
+            fn test_sync_address_reuse() {
+                let (wallet, descriptors, mut test_client) = init_single_sig();
+
+                test_client.receive(testutils! {
+                    @tx ( (@external descriptors, 0) => 50_000 )
+                });
+
+                wallet.sync(noop_progress(), None).unwrap();
+                assert_eq!(wallet.get_balance().unwrap(), 50_000);
+
+                test_client.receive(testutils! {
+                    @tx ( (@external descriptors, 0) => 25_000 )
+                });
+
+                wallet.sync(noop_progress(), None).unwrap();
+                assert_eq!(wallet.get_balance().unwrap(), 75_000);
+            }
+
+            #[test]
+            #[serial]
+            fn test_sync_receive_rbf_replaced() {
+                let (wallet, descriptors, mut test_client) = init_single_sig();
+
+                let txid = test_client.receive(testutils! {
+                    @tx ( (@external descriptors, 0) => 50_000 ) ( @replaceable true )
+                });
+
+                wallet.sync(noop_progress(), None).unwrap();
+
+                assert_eq!(wallet.get_balance().unwrap(), 50_000);
+                assert_eq!(wallet.list_transactions(false).unwrap().len(), 1);
+                assert_eq!(wallet.list_unspent().unwrap().len(), 1);
+
+                let list_tx_item = &wallet.list_transactions(false).unwrap()[0];
+                assert_eq!(list_tx_item.txid, txid);
+                assert_eq!(list_tx_item.received, 50_000);
+                assert_eq!(list_tx_item.sent, 0);
+                assert_eq!(list_tx_item.height, None);
+
+                let new_txid = test_client.bump_fee(&txid);
+
+                wallet.sync(noop_progress(), None).unwrap();
+
+                assert_eq!(wallet.get_balance().unwrap(), 50_000);
+                assert_eq!(wallet.list_transactions(false).unwrap().len(), 1);
+                assert_eq!(wallet.list_unspent().unwrap().len(), 1);
+
+                let list_tx_item = &wallet.list_transactions(false).unwrap()[0];
+                assert_eq!(list_tx_item.txid, new_txid);
+                assert_eq!(list_tx_item.received, 50_000);
+                assert_eq!(list_tx_item.sent, 0);
+                assert_eq!(list_tx_item.height, None);
+            }
+
+            #[test]
+            #[serial]
+            fn test_sync_reorg_block() {
+                let (wallet, descriptors, mut test_client) = init_single_sig();
+
+                let txid = test_client.receive(testutils! {
+                    @tx ( (@external descriptors, 0) => 50_000 ) ( @confirmations 1 ) ( @replaceable true )
+                });
+
+                wallet.sync(noop_progress(), None).unwrap();
+
+                assert_eq!(wallet.get_balance().unwrap(), 50_000);
+                assert_eq!(wallet.list_transactions(false).unwrap().len(), 1);
+                assert_eq!(wallet.list_unspent().unwrap().len(), 1);
+
+                let list_tx_item = &wallet.list_transactions(false).unwrap()[0];
+                assert_eq!(list_tx_item.txid, txid);
+                assert!(list_tx_item.height.is_some());
+
+                // Invalidate 1 block
+                test_client.invalidate(1);
+
+                wallet.sync(noop_progress(), None).unwrap();
+
+                assert_eq!(wallet.get_balance().unwrap(), 50_000);
+
+                let list_tx_item = &wallet.list_transactions(false).unwrap()[0];
+                assert_eq!(list_tx_item.txid, txid);
+                assert_eq!(list_tx_item.height, None);
+            }
+
+            #[test]
+            #[serial]
+            fn test_sync_after_send() {
+                let (wallet, descriptors, mut test_client) = init_single_sig();
+                println!("{}", descriptors.0);
+                let node_addr = test_client.get_node_address(None);
+
+                test_client.receive(testutils! {
+                    @tx ( (@external descriptors, 0) => 50_000 )
+                });
+
+                wallet.sync(noop_progress(), None).unwrap();
+                assert_eq!(wallet.get_balance().unwrap(), 50_000);
+
+                let mut builder = wallet.build_tx();
+                builder.add_recipient(node_addr.script_pubkey(), 25_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();
+                println!("{}", bitcoin::consensus::encode::serialize_hex(&tx));
+                wallet.broadcast(tx).unwrap();
+
+                wallet.sync(noop_progress(), None).unwrap();
+                assert_eq!(wallet.get_balance().unwrap(), details.received);
+
+                assert_eq!(wallet.list_transactions(false).unwrap().len(), 2);
+                assert_eq!(wallet.list_unspent().unwrap().len(), 1);
+            }
+
+            #[test]
+            #[serial]
+            fn test_sync_outgoing_from_scratch() {
+                let (wallet, descriptors, mut test_client) = init_single_sig();
+                let node_addr = test_client.get_node_address(None);
+
+                let received_txid = test_client.receive(testutils! {
+                    @tx ( (@external descriptors, 0) => 50_000 )
+                });
+
+                wallet.sync(noop_progress(), None).unwrap();
+                assert_eq!(wallet.get_balance().unwrap(), 50_000);
+
+                let mut builder = wallet.build_tx();
+                builder.add_recipient(node_addr.script_pubkey(), 25_000);
+                let (mut psbt, details) = builder.finish().unwrap();
+                let finalized = wallet.sign(&mut psbt, Default::default()).unwrap();
+                assert!(finalized, "Cannot finalize transaction");
+                let sent_txid = wallet.broadcast(psbt.extract_tx()).unwrap();
+
+                wallet.sync(noop_progress(), None).unwrap();
+                assert_eq!(wallet.get_balance().unwrap(), details.received);
+
+                // empty wallet
+                let wallet = get_wallet_from_descriptors(&descriptors);
+                wallet.sync(noop_progress(), None).unwrap();
+
+                let tx_map = wallet.list_transactions(false).unwrap().into_iter().map(|tx| (tx.txid, tx)).collect::<std::collections::HashMap<_, _>>();
+
+                let received = tx_map.get(&received_txid).unwrap();
+                assert_eq!(received.received, 50_000);
+                assert_eq!(received.sent, 0);
+
+                let sent = tx_map.get(&sent_txid).unwrap();
+                assert_eq!(sent.received, details.received);
+                assert_eq!(sent.sent, details.sent);
+                assert_eq!(sent.fees, details.fees);
+            }
+
+            #[test]
+            #[serial]
+            fn test_sync_long_change_chain() {
+                let (wallet, descriptors, mut test_client) = init_single_sig();
+                let node_addr = test_client.get_node_address(None);
+
+                test_client.receive(testutils! {
+                    @tx ( (@external descriptors, 0) => 50_000 )
+                });
+
+                wallet.sync(noop_progress(), None).unwrap();
+                assert_eq!(wallet.get_balance().unwrap(), 50_000);
+
+                let mut total_sent = 0;
+                for _ in 0..5 {
+                    let mut builder = wallet.build_tx();
+                    builder.add_recipient(node_addr.script_pubkey(), 5_000);
+                    let (mut psbt, details) = builder.finish().unwrap();
+                    let finalized = wallet.sign(&mut psbt, Default::default()).unwrap();
+                    assert!(finalized, "Cannot finalize transaction");
+                    wallet.broadcast(psbt.extract_tx()).unwrap();
+
+                    wallet.sync(noop_progress(), None).unwrap();
+
+                    total_sent += 5_000 + details.fees;
+                }
+
+                wallet.sync(noop_progress(), None).unwrap();
+                assert_eq!(wallet.get_balance().unwrap(), 50_000 - total_sent);
+
+                // empty wallet
+                let wallet = get_wallet_from_descriptors(&descriptors);
+                wallet.sync(noop_progress(), None).unwrap();
+                assert_eq!(wallet.get_balance().unwrap(), 50_000 - total_sent);
+            }
+
+            #[test]
+            #[serial]
+            fn test_sync_bump_fee() {
+                let (wallet, descriptors, mut test_client) = init_single_sig();
+                let node_addr = test_client.get_node_address(None);
+
+                test_client.receive(testutils! {
+                    @tx ( (@external descriptors, 0) => 50_000 ) (@confirmations 1)
+                });
+
+                wallet.sync(noop_progress(), None).unwrap();
+                assert_eq!(wallet.get_balance().unwrap(), 50_000);
+
+                let mut builder = wallet.build_tx();
+                builder.add_recipient(node_addr.script_pubkey().clone(), 5_000).enable_rbf();
+                let (mut psbt, details) = builder.finish().unwrap();
+                let finalized = wallet.sign(&mut psbt, Default::default()).unwrap();
+                assert!(finalized, "Cannot finalize transaction");
+                wallet.broadcast(psbt.extract_tx()).unwrap();
+                wallet.sync(noop_progress(), None).unwrap();
+                assert_eq!(wallet.get_balance().unwrap(), 50_000 - details.fees - 5_000);
+                assert_eq!(wallet.get_balance().unwrap(), details.received);
+
+                let mut builder = wallet.build_fee_bump(details.txid).unwrap();
+                builder.fee_rate(FeeRate::from_sat_per_vb(2.1));
+                let (mut new_psbt, new_details) = builder.finish().unwrap();
+                let finalized = wallet.sign(&mut new_psbt, Default::default()).unwrap();
+                assert!(finalized, "Cannot finalize transaction");
+                wallet.broadcast(new_psbt.extract_tx()).unwrap();
+                wallet.sync(noop_progress(), None).unwrap();
+                assert_eq!(wallet.get_balance().unwrap(), 50_000 - new_details.fees - 5_000);
+                assert_eq!(wallet.get_balance().unwrap(), new_details.received);
+
+                assert!(new_details.fees > details.fees);
+            }
+
+            #[test]
+            #[serial]
+            fn test_sync_bump_fee_remove_change() {
+                let (wallet, descriptors, mut test_client) = init_single_sig();
+                let node_addr = test_client.get_node_address(None);
+
+                test_client.receive(testutils! {
+                    @tx ( (@external descriptors, 0) => 50_000 ) (@confirmations 1)
+                });
+
+                wallet.sync(noop_progress(), None).unwrap();
+                assert_eq!(wallet.get_balance().unwrap(), 50_000);
+
+                let mut builder = wallet.build_tx();
+                builder.add_recipient(node_addr.script_pubkey().clone(), 49_000).enable_rbf();
+                let (mut psbt, details) = builder.finish().unwrap();
+                let finalized = wallet.sign(&mut psbt, Default::default()).unwrap();
+                assert!(finalized, "Cannot finalize transaction");
+                wallet.broadcast(psbt.extract_tx()).unwrap();
+                wallet.sync(noop_progress(), None).unwrap();
+                assert_eq!(wallet.get_balance().unwrap(), 1_000 - details.fees);
+                assert_eq!(wallet.get_balance().unwrap(), details.received);
+
+                let mut builder = wallet.build_fee_bump(details.txid).unwrap();
+                builder.fee_rate(FeeRate::from_sat_per_vb(5.0));
+                let (mut new_psbt, new_details) = builder.finish().unwrap();
+                let finalized = wallet.sign(&mut new_psbt, Default::default()).unwrap();
+                assert!(finalized, "Cannot finalize transaction");
+                wallet.broadcast(new_psbt.extract_tx()).unwrap();
+                wallet.sync(noop_progress(), None).unwrap();
+                assert_eq!(wallet.get_balance().unwrap(), 0);
+                assert_eq!(new_details.received, 0);
+
+                assert!(new_details.fees > details.fees);
+            }
+
+            #[test]
+            #[serial]
+            fn test_sync_bump_fee_add_input() {
+                let (wallet, descriptors, mut test_client) = init_single_sig();
+                let node_addr = test_client.get_node_address(None);
+
+                test_client.receive(testutils! {
+                    @tx ( (@external descriptors, 0) => 50_000, (@external descriptors, 1) => 25_000 ) (@confirmations 1)
+                });
+
+                wallet.sync(noop_progress(), None).unwrap();
+                assert_eq!(wallet.get_balance().unwrap(), 75_000);
+
+                let mut builder = wallet.build_tx();
+                builder.add_recipient(node_addr.script_pubkey().clone(), 49_000).enable_rbf();
+                let (mut psbt, details) = builder.finish().unwrap();
+                let finalized = wallet.sign(&mut psbt, Default::default()).unwrap();
+                assert!(finalized, "Cannot finalize transaction");
+                wallet.broadcast(psbt.extract_tx()).unwrap();
+                wallet.sync(noop_progress(), None).unwrap();
+                assert_eq!(wallet.get_balance().unwrap(), 26_000 - details.fees);
+                assert_eq!(details.received, 1_000 - details.fees);
+
+                let mut builder = wallet.build_fee_bump(details.txid).unwrap();
+                builder.fee_rate(FeeRate::from_sat_per_vb(10.0));
+                let (mut new_psbt, new_details) = builder.finish().unwrap();
+                let finalized = wallet.sign(&mut new_psbt, Default::default()).unwrap();
+                assert!(finalized, "Cannot finalize transaction");
+                wallet.broadcast(new_psbt.extract_tx()).unwrap();
+                wallet.sync(noop_progress(), None).unwrap();
+                assert_eq!(new_details.sent, 75_000);
+                assert_eq!(wallet.get_balance().unwrap(), new_details.received);
+            }
+
+            #[test]
+            #[serial]
+            fn test_sync_bump_fee_add_input_no_change() {
+                let (wallet, descriptors, mut test_client) = init_single_sig();
+                let node_addr = test_client.get_node_address(None);
+
+                test_client.receive(testutils! {
+                    @tx ( (@external descriptors, 0) => 50_000, (@external descriptors, 1) => 25_000 ) (@confirmations 1)
+                });
+
+                wallet.sync(noop_progress(), None).unwrap();
+                assert_eq!(wallet.get_balance().unwrap(), 75_000);
+
+                let mut builder = wallet.build_tx();
+                builder.add_recipient(node_addr.script_pubkey().clone(), 49_000).enable_rbf();
+                let (mut psbt, details) = builder.finish().unwrap();
+                let finalized = wallet.sign(&mut psbt, Default::default()).unwrap();
+                assert!(finalized, "Cannot finalize transaction");
+                wallet.broadcast(psbt.extract_tx()).unwrap();
+                wallet.sync(noop_progress(), None).unwrap();
+                assert_eq!(wallet.get_balance().unwrap(), 26_000 - details.fees);
+                assert_eq!(details.received, 1_000 - details.fees);
+
+                let mut builder = wallet.build_fee_bump(details.txid).unwrap();
+                builder.fee_rate(FeeRate::from_sat_per_vb(123.0));
+                let (mut new_psbt, new_details) = builder.finish().unwrap();
+                println!("{:#?}", new_details);
+
+                let finalized = wallet.sign(&mut new_psbt, Default::default()).unwrap();
+                assert!(finalized, "Cannot finalize transaction");
+                wallet.broadcast(new_psbt.extract_tx()).unwrap();
+                wallet.sync(noop_progress(), None).unwrap();
+                assert_eq!(new_details.sent, 75_000);
+                assert_eq!(wallet.get_balance().unwrap(), 0);
+                assert_eq!(new_details.received, 0);
+            }
+
+            #[test]
+            #[serial]
+            fn test_sync_receive_coinbase() {
+                let (wallet, descriptors, mut test_client) = init_single_sig();
+                let wallet_addr = wallet.get_address(New).unwrap();
+
+                wallet.sync(noop_progress(), None).unwrap();
+                assert_eq!(wallet.get_balance().unwrap(), 0);
+
+                test_client.generate(1, Some(wallet_addr));
+
+                wallet.sync(noop_progress(), None).unwrap();
+                assert!(wallet.get_balance().unwrap() > 0);
+            }
+        }
+    }
+}
index 29e43a4157e2bef71844cab473adfe7bcfdea007..333af54ff4f274dff9fe3934c46df81575baf02a 100644 (file)
@@ -11,6 +11,7 @@
 
 #[macro_use]
 extern crate serde_json;
+mod blockchain_tests;
 
 pub use serial_test::serial;
 
@@ -297,11 +298,12 @@ where
 }
 
 impl TestClient {
-    pub fn new() -> Self {
-        let url = env::var("BDK_RPC_URL").unwrap_or_else(|_| "127.0.0.1:18443".to_string());
-        let wallet = env::var("BDK_RPC_WALLET").unwrap_or_else(|_| "bdk-test".to_string());
-        let client =
-            RpcClient::new(format!("http://{}/wallet/{}", url, wallet), get_auth()).unwrap();
+    pub fn new(rpc_host_and_wallet: String, rpc_wallet_name: String) -> Self {
+        let client = RpcClient::new(
+            format!("http://{}/wallet/{}", rpc_host_and_wallet, rpc_wallet_name),
+            get_auth(),
+        )
+        .unwrap();
         let electrum = ElectrumClient::new(&get_electrum_url()).unwrap();
 
         TestClient { client, electrum }
@@ -562,3 +564,12 @@ impl Deref for TestClient {
         &self.client
     }
 }
+
+impl Default for TestClient {
+    fn default() -> Self {
+        let rpc_host_and_port =
+            env::var("BDK_RPC_URL").unwrap_or_else(|_| "127.0.0.1:18443".to_string());
+        let wallet = env::var("BDK_RPC_WALLET").unwrap_or_else(|_| "bdk-test".to_string());
+        Self::new(rpc_host_and_port, wallet)
+    }
+}