]> Untitled Git - bdk/commitdiff
chore(examples)!: update all examples to have `example_` prefix
authorLeonardo Lima <oleonardolima@users.noreply.github.com>
Thu, 12 Sep 2024 15:01:36 +0000 (12:01 -0300)
committerLeonardo Lima <oleonardolima@users.noreply.github.com>
Fri, 20 Sep 2024 16:54:07 +0000 (13:54 -0300)
19 files changed:
Cargo.toml
example-crates/example_wallet_electrum/Cargo.toml [new file with mode: 0644]
example-crates/example_wallet_electrum/src/main.rs [new file with mode: 0644]
example-crates/example_wallet_esplora_async/Cargo.toml [new file with mode: 0644]
example-crates/example_wallet_esplora_async/src/main.rs [new file with mode: 0644]
example-crates/example_wallet_esplora_blocking/Cargo.toml [new file with mode: 0644]
example-crates/example_wallet_esplora_blocking/src/main.rs [new file with mode: 0644]
example-crates/example_wallet_rpc/Cargo.toml [new file with mode: 0644]
example-crates/example_wallet_rpc/README.md [new file with mode: 0644]
example-crates/example_wallet_rpc/src/main.rs [new file with mode: 0644]
example-crates/wallet_electrum/Cargo.toml [deleted file]
example-crates/wallet_electrum/src/main.rs [deleted file]
example-crates/wallet_esplora_async/Cargo.toml [deleted file]
example-crates/wallet_esplora_async/src/main.rs [deleted file]
example-crates/wallet_esplora_blocking/Cargo.toml [deleted file]
example-crates/wallet_esplora_blocking/src/main.rs [deleted file]
example-crates/wallet_rpc/Cargo.toml [deleted file]
example-crates/wallet_rpc/README.md [deleted file]
example-crates/wallet_rpc/src/main.rs [deleted file]

index a6e6eb6e609a7d63643431c3f28c66db826b8e38..2abc16bd8136af4074cb2cac9af7b230f784d18a 100644 (file)
@@ -13,10 +13,10 @@ members = [
     "example-crates/example_electrum",
     "example-crates/example_esplora",
     "example-crates/example_bitcoind_rpc_polling",
-    "example-crates/wallet_electrum",
-    "example-crates/wallet_esplora_blocking",
-    "example-crates/wallet_esplora_async",
-    "example-crates/wallet_rpc",
+    "example-crates/example_wallet_electrum",
+    "example-crates/example_wallet_esplora_blocking",
+    "example-crates/example_wallet_esplora_async",
+    "example-crates/example_wallet_rpc",
 ]
 
 [workspace.package]
diff --git a/example-crates/example_wallet_electrum/Cargo.toml b/example-crates/example_wallet_electrum/Cargo.toml
new file mode 100644 (file)
index 0000000..07ba60d
--- /dev/null
@@ -0,0 +1,9 @@
+[package]
+name = "example_wallet_electrum"
+version = "0.2.0"
+edition = "2021"
+
+[dependencies]
+bdk_wallet = { path = "../../crates/wallet", features = ["file_store"] }
+bdk_electrum = { path = "../../crates/electrum" }
+anyhow = "1"
diff --git a/example-crates/example_wallet_electrum/src/main.rs b/example-crates/example_wallet_electrum/src/main.rs
new file mode 100644 (file)
index 0000000..f3320d8
--- /dev/null
@@ -0,0 +1,98 @@
+use bdk_wallet::file_store::Store;
+use bdk_wallet::Wallet;
+use std::io::Write;
+
+use bdk_electrum::electrum_client;
+use bdk_electrum::BdkElectrumClient;
+use bdk_wallet::bitcoin::Amount;
+use bdk_wallet::bitcoin::Network;
+use bdk_wallet::chain::collections::HashSet;
+use bdk_wallet::{KeychainKind, SignOptions};
+
+const DB_MAGIC: &str = "bdk_wallet_electrum_example";
+const SEND_AMOUNT: Amount = Amount::from_sat(5000);
+const STOP_GAP: usize = 50;
+const BATCH_SIZE: usize = 5;
+
+const NETWORK: Network = Network::Testnet;
+const EXTERNAL_DESC: &str = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/1'/0'/0/*)";
+const INTERNAL_DESC: &str = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/1'/0'/1/*)";
+const ELECTRUM_URL: &str = "ssl://electrum.blockstream.info:60002";
+
+fn main() -> Result<(), anyhow::Error> {
+    let db_path = "bdk-electrum-example.db";
+
+    let mut db = Store::<bdk_wallet::ChangeSet>::open_or_create_new(DB_MAGIC.as_bytes(), db_path)?;
+
+    let wallet_opt = Wallet::load()
+        .descriptor(KeychainKind::External, Some(EXTERNAL_DESC))
+        .descriptor(KeychainKind::Internal, Some(INTERNAL_DESC))
+        .extract_keys()
+        .check_network(NETWORK)
+        .load_wallet(&mut db)?;
+    let mut wallet = match wallet_opt {
+        Some(wallet) => wallet,
+        None => Wallet::create(EXTERNAL_DESC, INTERNAL_DESC)
+            .network(NETWORK)
+            .create_wallet(&mut db)?,
+    };
+
+    let address = wallet.next_unused_address(KeychainKind::External);
+    wallet.persist(&mut db)?;
+    println!("Generated Address: {}", address);
+
+    let balance = wallet.balance();
+    println!("Wallet balance before syncing: {}", balance.total());
+
+    print!("Syncing...");
+    let client = BdkElectrumClient::new(electrum_client::Client::new(ELECTRUM_URL)?);
+
+    // Populate the electrum client's transaction cache so it doesn't redownload transaction we
+    // already have.
+    client.populate_tx_cache(wallet.tx_graph().full_txs().map(|tx_node| tx_node.tx));
+
+    let request = wallet.start_full_scan().inspect({
+        let mut stdout = std::io::stdout();
+        let mut once = HashSet::<KeychainKind>::new();
+        move |k, spk_i, _| {
+            if once.insert(k) {
+                print!("\nScanning keychain [{:?}]", k);
+            }
+            print!(" {:<3}", spk_i);
+            stdout.flush().expect("must flush");
+        }
+    });
+
+    let update = client.full_scan(request, STOP_GAP, BATCH_SIZE, false)?;
+
+    println!();
+
+    wallet.apply_update(update)?;
+    wallet.persist(&mut db)?;
+
+    let balance = wallet.balance();
+    println!("Wallet balance after syncing: {}", balance.total());
+
+    if balance.total() < SEND_AMOUNT {
+        println!(
+            "Please send at least {} to the receiving address",
+            SEND_AMOUNT
+        );
+        std::process::exit(0);
+    }
+
+    let mut tx_builder = wallet.build_tx();
+    tx_builder
+        .add_recipient(address.script_pubkey(), SEND_AMOUNT)
+        .enable_rbf();
+
+    let mut psbt = tx_builder.finish()?;
+    let finalized = wallet.sign(&mut psbt, SignOptions::default())?;
+    assert!(finalized);
+
+    let tx = psbt.extract_tx()?;
+    client.transaction_broadcast(&tx)?;
+    println!("Tx broadcasted! Txid: {}", tx.compute_txid());
+
+    Ok(())
+}
diff --git a/example-crates/example_wallet_esplora_async/Cargo.toml b/example-crates/example_wallet_esplora_async/Cargo.toml
new file mode 100644 (file)
index 0000000..2121b72
--- /dev/null
@@ -0,0 +1,12 @@
+[package]
+name = "example_wallet_esplora_async"
+version = "0.2.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+bdk_wallet = { path = "../../crates/wallet", features = ["rusqlite"] }
+bdk_esplora = { path = "../../crates/esplora", features = ["async-https"] }
+tokio = { version = "1", features = ["rt", "rt-multi-thread", "macros"] }
+anyhow = "1"
diff --git a/example-crates/example_wallet_esplora_async/src/main.rs b/example-crates/example_wallet_esplora_async/src/main.rs
new file mode 100644 (file)
index 0000000..4133982
--- /dev/null
@@ -0,0 +1,93 @@
+use std::{collections::BTreeSet, io::Write};
+
+use anyhow::Ok;
+use bdk_esplora::{esplora_client, EsploraAsyncExt};
+use bdk_wallet::{
+    bitcoin::{Amount, Network},
+    rusqlite::Connection,
+    KeychainKind, SignOptions, Wallet,
+};
+
+const SEND_AMOUNT: Amount = Amount::from_sat(5000);
+const STOP_GAP: usize = 5;
+const PARALLEL_REQUESTS: usize = 5;
+
+const DB_PATH: &str = "bdk-example-esplora-async.sqlite";
+const NETWORK: Network = Network::Signet;
+const EXTERNAL_DESC: &str = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/1'/0'/0/*)";
+const INTERNAL_DESC: &str = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/1'/0'/1/*)";
+const ESPLORA_URL: &str = "http://signet.bitcoindevkit.net";
+
+#[tokio::main]
+async fn main() -> Result<(), anyhow::Error> {
+    let mut conn = Connection::open(DB_PATH)?;
+
+    let wallet_opt = Wallet::load()
+        .descriptor(KeychainKind::External, Some(EXTERNAL_DESC))
+        .descriptor(KeychainKind::Internal, Some(INTERNAL_DESC))
+        .extract_keys()
+        .check_network(NETWORK)
+        .load_wallet(&mut conn)?;
+    let mut wallet = match wallet_opt {
+        Some(wallet) => wallet,
+        None => Wallet::create(EXTERNAL_DESC, INTERNAL_DESC)
+            .network(NETWORK)
+            .create_wallet(&mut conn)?,
+    };
+
+    let address = wallet.next_unused_address(KeychainKind::External);
+    wallet.persist(&mut conn)?;
+    println!("Next unused address: ({}) {}", address.index, address);
+
+    let balance = wallet.balance();
+    println!("Wallet balance before syncing: {}", balance.total());
+
+    print!("Syncing...");
+    let client = esplora_client::Builder::new(ESPLORA_URL).build_async()?;
+
+    let request = wallet.start_full_scan().inspect({
+        let mut stdout = std::io::stdout();
+        let mut once = BTreeSet::<KeychainKind>::new();
+        move |keychain, spk_i, _| {
+            if once.insert(keychain) {
+                print!("\nScanning keychain [{:?}]", keychain);
+            }
+            print!(" {:<3}", spk_i);
+            stdout.flush().expect("must flush")
+        }
+    });
+
+    let update = client
+        .full_scan(request, STOP_GAP, PARALLEL_REQUESTS)
+        .await?;
+
+    wallet.apply_update(update)?;
+    wallet.persist(&mut conn)?;
+    println!();
+
+    let balance = wallet.balance();
+    println!("Wallet balance after syncing: {}", balance.total());
+
+    if balance.total() < SEND_AMOUNT {
+        println!(
+            "Please send at least {} to the receiving address",
+            SEND_AMOUNT
+        );
+        std::process::exit(0);
+    }
+
+    let mut tx_builder = wallet.build_tx();
+    tx_builder
+        .add_recipient(address.script_pubkey(), SEND_AMOUNT)
+        .enable_rbf();
+
+    let mut psbt = tx_builder.finish()?;
+    let finalized = wallet.sign(&mut psbt, SignOptions::default())?;
+    assert!(finalized);
+
+    let tx = psbt.extract_tx()?;
+    client.broadcast(&tx).await?;
+    println!("Tx broadcasted! Txid: {}", tx.compute_txid());
+
+    Ok(())
+}
diff --git a/example-crates/example_wallet_esplora_blocking/Cargo.toml b/example-crates/example_wallet_esplora_blocking/Cargo.toml
new file mode 100644 (file)
index 0000000..f47d040
--- /dev/null
@@ -0,0 +1,12 @@
+[package]
+name = "example_wallet_esplora_blocking"
+version = "0.2.0"
+edition = "2021"
+publish = false
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+bdk_wallet = { path = "../../crates/wallet", features = ["file_store"] }
+bdk_esplora = { path = "../../crates/esplora", features = ["blocking"] }
+anyhow = "1"
diff --git a/example-crates/example_wallet_esplora_blocking/src/main.rs b/example-crates/example_wallet_esplora_blocking/src/main.rs
new file mode 100644 (file)
index 0000000..d12dbd9
--- /dev/null
@@ -0,0 +1,93 @@
+use std::{collections::BTreeSet, io::Write};
+
+use bdk_esplora::{esplora_client, EsploraExt};
+use bdk_wallet::{
+    bitcoin::{Amount, Network},
+    file_store::Store,
+    KeychainKind, SignOptions, Wallet,
+};
+
+const DB_MAGIC: &str = "bdk_wallet_esplora_example";
+const DB_PATH: &str = "bdk-example-esplora-blocking.db";
+const SEND_AMOUNT: Amount = Amount::from_sat(5000);
+const STOP_GAP: usize = 5;
+const PARALLEL_REQUESTS: usize = 5;
+
+const NETWORK: Network = Network::Signet;
+const EXTERNAL_DESC: &str = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/1'/0'/0/*)";
+const INTERNAL_DESC: &str = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/1'/0'/1/*)";
+const ESPLORA_URL: &str = "http://signet.bitcoindevkit.net";
+
+fn main() -> Result<(), anyhow::Error> {
+    let mut db = Store::<bdk_wallet::ChangeSet>::open_or_create_new(DB_MAGIC.as_bytes(), DB_PATH)?;
+
+    let wallet_opt = Wallet::load()
+        .descriptor(KeychainKind::External, Some(EXTERNAL_DESC))
+        .descriptor(KeychainKind::Internal, Some(INTERNAL_DESC))
+        .extract_keys()
+        .check_network(NETWORK)
+        .load_wallet(&mut db)?;
+    let mut wallet = match wallet_opt {
+        Some(wallet) => wallet,
+        None => Wallet::create(EXTERNAL_DESC, INTERNAL_DESC)
+            .network(NETWORK)
+            .create_wallet(&mut db)?,
+    };
+
+    let address = wallet.next_unused_address(KeychainKind::External);
+    wallet.persist(&mut db)?;
+    println!(
+        "Next unused address: ({}) {}",
+        address.index, address.address
+    );
+
+    let balance = wallet.balance();
+    println!("Wallet balance before syncing: {}", balance.total());
+
+    print!("Syncing...");
+    let client = esplora_client::Builder::new(ESPLORA_URL).build_blocking();
+
+    let request = wallet.start_full_scan().inspect({
+        let mut stdout = std::io::stdout();
+        let mut once = BTreeSet::<KeychainKind>::new();
+        move |keychain, spk_i, _| {
+            if once.insert(keychain) {
+                print!("\nScanning keychain [{:?}] ", keychain);
+            }
+            print!(" {:<3}", spk_i);
+            stdout.flush().expect("must flush")
+        }
+    });
+
+    let update = client.full_scan(request, STOP_GAP, PARALLEL_REQUESTS)?;
+
+    wallet.apply_update(update)?;
+    wallet.persist(&mut db)?;
+    println!();
+
+    let balance = wallet.balance();
+    println!("Wallet balance after syncing: {}", balance.total());
+
+    if balance.total() < SEND_AMOUNT {
+        println!(
+            "Please send at least {} to the receiving address",
+            SEND_AMOUNT
+        );
+        std::process::exit(0);
+    }
+
+    let mut tx_builder = wallet.build_tx();
+    tx_builder
+        .add_recipient(address.script_pubkey(), SEND_AMOUNT)
+        .enable_rbf();
+
+    let mut psbt = tx_builder.finish()?;
+    let finalized = wallet.sign(&mut psbt, SignOptions::default())?;
+    assert!(finalized);
+
+    let tx = psbt.extract_tx()?;
+    client.broadcast(&tx)?;
+    println!("Tx broadcasted! Txid: {}", tx.compute_txid());
+
+    Ok(())
+}
diff --git a/example-crates/example_wallet_rpc/Cargo.toml b/example-crates/example_wallet_rpc/Cargo.toml
new file mode 100644 (file)
index 0000000..558f43f
--- /dev/null
@@ -0,0 +1,14 @@
+[package]
+name = "example_wallet_rpc"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+bdk_wallet = { path = "../../crates/wallet", features = ["file_store"] }
+bdk_bitcoind_rpc = { path = "../../crates/bitcoind_rpc" }
+
+anyhow = "1"
+clap = { version = "3.2.25", features = ["derive", "env"] }
+ctrlc = "2.0.1"
diff --git a/example-crates/example_wallet_rpc/README.md b/example-crates/example_wallet_rpc/README.md
new file mode 100644 (file)
index 0000000..ea2918a
--- /dev/null
@@ -0,0 +1,45 @@
+# Wallet RPC Example 
+
+```
+$ cargo run --bin example_wallet_rpc -- --help
+
+example_wallet_rpc 0.1.0
+Bitcoind RPC example using `bdk_wallet::Wallet`
+
+USAGE:
+    example_wallet_rpc [OPTIONS] <DESCRIPTOR> [CHANGE_DESCRIPTOR]
+
+ARGS:
+    <DESCRIPTOR>           Wallet descriptor [env: DESCRIPTOR=]
+    <CHANGE_DESCRIPTOR>    Wallet change descriptor [env: CHANGE_DESCRIPTOR=]
+
+OPTIONS:
+        --db-path <DB_PATH>
+            Where to store wallet data [env: BDK_DB_PATH=] [default: .bdk_wallet_rpc_example.db]
+
+    -h, --help
+            Print help information
+
+        --network <NETWORK>
+            Bitcoin network to connect to [env: BITCOIN_NETWORK=] [default: testnet]
+
+        --rpc-cookie <RPC_COOKIE>
+            RPC auth cookie file [env: RPC_COOKIE=]
+
+        --rpc-pass <RPC_PASS>
+            RPC auth password [env: RPC_PASS=]
+
+        --rpc-user <RPC_USER>
+            RPC auth username [env: RPC_USER=]
+
+        --start-height <START_HEIGHT>
+            Earliest block height to start sync from [env: START_HEIGHT=] [default: 481824]
+
+        --url <URL>
+            RPC URL [env: RPC_URL=] [default: 127.0.0.1:8332]
+
+    -V, --version
+            Print version information
+
+```
+
diff --git a/example-crates/example_wallet_rpc/src/main.rs b/example-crates/example_wallet_rpc/src/main.rs
new file mode 100644 (file)
index 0000000..204224b
--- /dev/null
@@ -0,0 +1,190 @@
+use bdk_bitcoind_rpc::{
+    bitcoincore_rpc::{Auth, Client, RpcApi},
+    Emitter,
+};
+use bdk_wallet::{
+    bitcoin::{Block, Network, Transaction},
+    file_store::Store,
+    KeychainKind, Wallet,
+};
+use clap::{self, Parser};
+use std::{path::PathBuf, sync::mpsc::sync_channel, thread::spawn, time::Instant};
+
+const DB_MAGIC: &str = "bdk-rpc-wallet-example";
+
+/// Bitcoind RPC example using `bdk_wallet::Wallet`.
+///
+/// This syncs the chain block-by-block and prints the current balance, transaction count and UTXO
+/// count.
+#[derive(Parser, Debug)]
+#[clap(author, version, about, long_about = None)]
+#[clap(propagate_version = true)]
+pub struct Args {
+    /// Wallet descriptor
+    #[clap(env = "DESCRIPTOR")]
+    pub descriptor: String,
+    /// Wallet change descriptor
+    #[clap(env = "CHANGE_DESCRIPTOR")]
+    pub change_descriptor: String,
+    /// Earliest block height to start sync from
+    #[clap(env = "START_HEIGHT", long, default_value = "481824")]
+    pub start_height: u32,
+    /// Bitcoin network to connect to
+    #[clap(env = "BITCOIN_NETWORK", long, default_value = "testnet")]
+    pub network: Network,
+    /// Where to store wallet data
+    #[clap(
+        env = "BDK_DB_PATH",
+        long,
+        default_value = ".bdk_wallet_rpc_example.db"
+    )]
+    pub db_path: PathBuf,
+
+    /// RPC URL
+    #[clap(env = "RPC_URL", long, default_value = "127.0.0.1:8332")]
+    pub url: String,
+    /// RPC auth cookie file
+    #[clap(env = "RPC_COOKIE", long)]
+    pub rpc_cookie: Option<PathBuf>,
+    /// RPC auth username
+    #[clap(env = "RPC_USER", long)]
+    pub rpc_user: Option<String>,
+    /// RPC auth password
+    #[clap(env = "RPC_PASS", long)]
+    pub rpc_pass: Option<String>,
+}
+
+impl Args {
+    fn client(&self) -> anyhow::Result<Client> {
+        Ok(Client::new(
+            &self.url,
+            match (&self.rpc_cookie, &self.rpc_user, &self.rpc_pass) {
+                (None, None, None) => Auth::None,
+                (Some(path), _, _) => Auth::CookieFile(path.clone()),
+                (_, Some(user), Some(pass)) => Auth::UserPass(user.clone(), pass.clone()),
+                (_, Some(_), None) => panic!("rpc auth: missing rpc_pass"),
+                (_, None, Some(_)) => panic!("rpc auth: missing rpc_user"),
+            },
+        )?)
+    }
+}
+
+#[derive(Debug)]
+enum Emission {
+    SigTerm,
+    Block(bdk_bitcoind_rpc::BlockEvent<Block>),
+    Mempool(Vec<(Transaction, u64)>),
+}
+
+fn main() -> anyhow::Result<()> {
+    let args = Args::parse();
+
+    let rpc_client = args.client()?;
+    println!(
+        "Connected to Bitcoin Core RPC at {:?}",
+        rpc_client.get_blockchain_info().unwrap()
+    );
+
+    let start_load_wallet = Instant::now();
+    let mut db =
+        Store::<bdk_wallet::ChangeSet>::open_or_create_new(DB_MAGIC.as_bytes(), args.db_path)?;
+    let wallet_opt = Wallet::load()
+        .descriptor(KeychainKind::External, Some(args.descriptor.clone()))
+        .descriptor(KeychainKind::Internal, Some(args.change_descriptor.clone()))
+        .extract_keys()
+        .check_network(args.network)
+        .load_wallet(&mut db)?;
+    let mut wallet = match wallet_opt {
+        Some(wallet) => wallet,
+        None => Wallet::create(args.descriptor, args.change_descriptor)
+            .network(args.network)
+            .create_wallet(&mut db)?,
+    };
+    println!(
+        "Loaded wallet in {}s",
+        start_load_wallet.elapsed().as_secs_f32()
+    );
+
+    let balance = wallet.balance();
+    println!("Wallet balance before syncing: {}", balance.total());
+
+    let wallet_tip = wallet.latest_checkpoint();
+    println!(
+        "Wallet tip: {} at height {}",
+        wallet_tip.hash(),
+        wallet_tip.height()
+    );
+
+    let (sender, receiver) = sync_channel::<Emission>(21);
+
+    let signal_sender = sender.clone();
+    ctrlc::set_handler(move || {
+        signal_sender
+            .send(Emission::SigTerm)
+            .expect("failed to send sigterm")
+    });
+
+    let emitter_tip = wallet_tip.clone();
+    spawn(move || -> Result<(), anyhow::Error> {
+        let mut emitter = Emitter::new(&rpc_client, emitter_tip, args.start_height);
+        while let Some(emission) = emitter.next_block()? {
+            sender.send(Emission::Block(emission))?;
+        }
+        sender.send(Emission::Mempool(emitter.mempool()?))?;
+        Ok(())
+    });
+
+    let mut blocks_received = 0_usize;
+    for emission in receiver {
+        match emission {
+            Emission::SigTerm => {
+                println!("Sigterm received, exiting...");
+                break;
+            }
+            Emission::Block(block_emission) => {
+                blocks_received += 1;
+                let height = block_emission.block_height();
+                let hash = block_emission.block_hash();
+                let connected_to = block_emission.connected_to();
+                let start_apply_block = Instant::now();
+                wallet.apply_block_connected_to(&block_emission.block, height, connected_to)?;
+                wallet.persist(&mut db)?;
+                let elapsed = start_apply_block.elapsed().as_secs_f32();
+                println!(
+                    "Applied block {} at height {} in {}s",
+                    hash, height, elapsed
+                );
+            }
+            Emission::Mempool(mempool_emission) => {
+                let start_apply_mempool = Instant::now();
+                wallet.apply_unconfirmed_txs(mempool_emission);
+                wallet.persist(&mut db)?;
+                println!(
+                    "Applied unconfirmed transactions in {}s",
+                    start_apply_mempool.elapsed().as_secs_f32()
+                );
+                break;
+            }
+        }
+    }
+    let wallet_tip_end = wallet.latest_checkpoint();
+    let balance = wallet.balance();
+    println!(
+        "Synced {} blocks in {}s",
+        blocks_received,
+        start_load_wallet.elapsed().as_secs_f32(),
+    );
+    println!(
+        "Wallet tip is '{}:{}'",
+        wallet_tip_end.height(),
+        wallet_tip_end.hash()
+    );
+    println!("Wallet balance is {}", balance.total());
+    println!(
+        "Wallet has {} transactions and {} utxos",
+        wallet.transactions().count(),
+        wallet.list_unspent().count()
+    );
+
+    Ok(())
+}
diff --git a/example-crates/wallet_electrum/Cargo.toml b/example-crates/wallet_electrum/Cargo.toml
deleted file mode 100644 (file)
index 10b662e..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-[package]
-name = "wallet_electrum_example"
-version = "0.2.0"
-edition = "2021"
-
-[dependencies]
-bdk_wallet = { path = "../../crates/wallet", features = ["file_store"] }
-bdk_electrum = { path = "../../crates/electrum" }
-anyhow = "1"
diff --git a/example-crates/wallet_electrum/src/main.rs b/example-crates/wallet_electrum/src/main.rs
deleted file mode 100644 (file)
index f3320d8..0000000
+++ /dev/null
@@ -1,98 +0,0 @@
-use bdk_wallet::file_store::Store;
-use bdk_wallet::Wallet;
-use std::io::Write;
-
-use bdk_electrum::electrum_client;
-use bdk_electrum::BdkElectrumClient;
-use bdk_wallet::bitcoin::Amount;
-use bdk_wallet::bitcoin::Network;
-use bdk_wallet::chain::collections::HashSet;
-use bdk_wallet::{KeychainKind, SignOptions};
-
-const DB_MAGIC: &str = "bdk_wallet_electrum_example";
-const SEND_AMOUNT: Amount = Amount::from_sat(5000);
-const STOP_GAP: usize = 50;
-const BATCH_SIZE: usize = 5;
-
-const NETWORK: Network = Network::Testnet;
-const EXTERNAL_DESC: &str = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/1'/0'/0/*)";
-const INTERNAL_DESC: &str = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/1'/0'/1/*)";
-const ELECTRUM_URL: &str = "ssl://electrum.blockstream.info:60002";
-
-fn main() -> Result<(), anyhow::Error> {
-    let db_path = "bdk-electrum-example.db";
-
-    let mut db = Store::<bdk_wallet::ChangeSet>::open_or_create_new(DB_MAGIC.as_bytes(), db_path)?;
-
-    let wallet_opt = Wallet::load()
-        .descriptor(KeychainKind::External, Some(EXTERNAL_DESC))
-        .descriptor(KeychainKind::Internal, Some(INTERNAL_DESC))
-        .extract_keys()
-        .check_network(NETWORK)
-        .load_wallet(&mut db)?;
-    let mut wallet = match wallet_opt {
-        Some(wallet) => wallet,
-        None => Wallet::create(EXTERNAL_DESC, INTERNAL_DESC)
-            .network(NETWORK)
-            .create_wallet(&mut db)?,
-    };
-
-    let address = wallet.next_unused_address(KeychainKind::External);
-    wallet.persist(&mut db)?;
-    println!("Generated Address: {}", address);
-
-    let balance = wallet.balance();
-    println!("Wallet balance before syncing: {}", balance.total());
-
-    print!("Syncing...");
-    let client = BdkElectrumClient::new(electrum_client::Client::new(ELECTRUM_URL)?);
-
-    // Populate the electrum client's transaction cache so it doesn't redownload transaction we
-    // already have.
-    client.populate_tx_cache(wallet.tx_graph().full_txs().map(|tx_node| tx_node.tx));
-
-    let request = wallet.start_full_scan().inspect({
-        let mut stdout = std::io::stdout();
-        let mut once = HashSet::<KeychainKind>::new();
-        move |k, spk_i, _| {
-            if once.insert(k) {
-                print!("\nScanning keychain [{:?}]", k);
-            }
-            print!(" {:<3}", spk_i);
-            stdout.flush().expect("must flush");
-        }
-    });
-
-    let update = client.full_scan(request, STOP_GAP, BATCH_SIZE, false)?;
-
-    println!();
-
-    wallet.apply_update(update)?;
-    wallet.persist(&mut db)?;
-
-    let balance = wallet.balance();
-    println!("Wallet balance after syncing: {}", balance.total());
-
-    if balance.total() < SEND_AMOUNT {
-        println!(
-            "Please send at least {} to the receiving address",
-            SEND_AMOUNT
-        );
-        std::process::exit(0);
-    }
-
-    let mut tx_builder = wallet.build_tx();
-    tx_builder
-        .add_recipient(address.script_pubkey(), SEND_AMOUNT)
-        .enable_rbf();
-
-    let mut psbt = tx_builder.finish()?;
-    let finalized = wallet.sign(&mut psbt, SignOptions::default())?;
-    assert!(finalized);
-
-    let tx = psbt.extract_tx()?;
-    client.transaction_broadcast(&tx)?;
-    println!("Tx broadcasted! Txid: {}", tx.compute_txid());
-
-    Ok(())
-}
diff --git a/example-crates/wallet_esplora_async/Cargo.toml b/example-crates/wallet_esplora_async/Cargo.toml
deleted file mode 100644 (file)
index aa18a5e..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-[package]
-name = "wallet_esplora_async"
-version = "0.2.0"
-edition = "2021"
-
-# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
-
-[dependencies]
-bdk_wallet = { path = "../../crates/wallet", features = ["rusqlite"] }
-bdk_esplora = { path = "../../crates/esplora", features = ["async-https"] }
-tokio = { version = "1", features = ["rt", "rt-multi-thread", "macros"] }
-anyhow = "1"
diff --git a/example-crates/wallet_esplora_async/src/main.rs b/example-crates/wallet_esplora_async/src/main.rs
deleted file mode 100644 (file)
index 4133982..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-use std::{collections::BTreeSet, io::Write};
-
-use anyhow::Ok;
-use bdk_esplora::{esplora_client, EsploraAsyncExt};
-use bdk_wallet::{
-    bitcoin::{Amount, Network},
-    rusqlite::Connection,
-    KeychainKind, SignOptions, Wallet,
-};
-
-const SEND_AMOUNT: Amount = Amount::from_sat(5000);
-const STOP_GAP: usize = 5;
-const PARALLEL_REQUESTS: usize = 5;
-
-const DB_PATH: &str = "bdk-example-esplora-async.sqlite";
-const NETWORK: Network = Network::Signet;
-const EXTERNAL_DESC: &str = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/1'/0'/0/*)";
-const INTERNAL_DESC: &str = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/1'/0'/1/*)";
-const ESPLORA_URL: &str = "http://signet.bitcoindevkit.net";
-
-#[tokio::main]
-async fn main() -> Result<(), anyhow::Error> {
-    let mut conn = Connection::open(DB_PATH)?;
-
-    let wallet_opt = Wallet::load()
-        .descriptor(KeychainKind::External, Some(EXTERNAL_DESC))
-        .descriptor(KeychainKind::Internal, Some(INTERNAL_DESC))
-        .extract_keys()
-        .check_network(NETWORK)
-        .load_wallet(&mut conn)?;
-    let mut wallet = match wallet_opt {
-        Some(wallet) => wallet,
-        None => Wallet::create(EXTERNAL_DESC, INTERNAL_DESC)
-            .network(NETWORK)
-            .create_wallet(&mut conn)?,
-    };
-
-    let address = wallet.next_unused_address(KeychainKind::External);
-    wallet.persist(&mut conn)?;
-    println!("Next unused address: ({}) {}", address.index, address);
-
-    let balance = wallet.balance();
-    println!("Wallet balance before syncing: {}", balance.total());
-
-    print!("Syncing...");
-    let client = esplora_client::Builder::new(ESPLORA_URL).build_async()?;
-
-    let request = wallet.start_full_scan().inspect({
-        let mut stdout = std::io::stdout();
-        let mut once = BTreeSet::<KeychainKind>::new();
-        move |keychain, spk_i, _| {
-            if once.insert(keychain) {
-                print!("\nScanning keychain [{:?}]", keychain);
-            }
-            print!(" {:<3}", spk_i);
-            stdout.flush().expect("must flush")
-        }
-    });
-
-    let update = client
-        .full_scan(request, STOP_GAP, PARALLEL_REQUESTS)
-        .await?;
-
-    wallet.apply_update(update)?;
-    wallet.persist(&mut conn)?;
-    println!();
-
-    let balance = wallet.balance();
-    println!("Wallet balance after syncing: {}", balance.total());
-
-    if balance.total() < SEND_AMOUNT {
-        println!(
-            "Please send at least {} to the receiving address",
-            SEND_AMOUNT
-        );
-        std::process::exit(0);
-    }
-
-    let mut tx_builder = wallet.build_tx();
-    tx_builder
-        .add_recipient(address.script_pubkey(), SEND_AMOUNT)
-        .enable_rbf();
-
-    let mut psbt = tx_builder.finish()?;
-    let finalized = wallet.sign(&mut psbt, SignOptions::default())?;
-    assert!(finalized);
-
-    let tx = psbt.extract_tx()?;
-    client.broadcast(&tx).await?;
-    println!("Tx broadcasted! Txid: {}", tx.compute_txid());
-
-    Ok(())
-}
diff --git a/example-crates/wallet_esplora_blocking/Cargo.toml b/example-crates/wallet_esplora_blocking/Cargo.toml
deleted file mode 100644 (file)
index 4228c98..0000000
+++ /dev/null
@@ -1,12 +0,0 @@
-[package]
-name = "wallet_esplora_blocking"
-version = "0.2.0"
-edition = "2021"
-publish = false
-
-# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
-
-[dependencies]
-bdk_wallet = { path = "../../crates/wallet", features = ["file_store"] }
-bdk_esplora = { path = "../../crates/esplora", features = ["blocking"] }
-anyhow = "1"
diff --git a/example-crates/wallet_esplora_blocking/src/main.rs b/example-crates/wallet_esplora_blocking/src/main.rs
deleted file mode 100644 (file)
index d12dbd9..0000000
+++ /dev/null
@@ -1,93 +0,0 @@
-use std::{collections::BTreeSet, io::Write};
-
-use bdk_esplora::{esplora_client, EsploraExt};
-use bdk_wallet::{
-    bitcoin::{Amount, Network},
-    file_store::Store,
-    KeychainKind, SignOptions, Wallet,
-};
-
-const DB_MAGIC: &str = "bdk_wallet_esplora_example";
-const DB_PATH: &str = "bdk-example-esplora-blocking.db";
-const SEND_AMOUNT: Amount = Amount::from_sat(5000);
-const STOP_GAP: usize = 5;
-const PARALLEL_REQUESTS: usize = 5;
-
-const NETWORK: Network = Network::Signet;
-const EXTERNAL_DESC: &str = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/1'/0'/0/*)";
-const INTERNAL_DESC: &str = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/1'/0'/1/*)";
-const ESPLORA_URL: &str = "http://signet.bitcoindevkit.net";
-
-fn main() -> Result<(), anyhow::Error> {
-    let mut db = Store::<bdk_wallet::ChangeSet>::open_or_create_new(DB_MAGIC.as_bytes(), DB_PATH)?;
-
-    let wallet_opt = Wallet::load()
-        .descriptor(KeychainKind::External, Some(EXTERNAL_DESC))
-        .descriptor(KeychainKind::Internal, Some(INTERNAL_DESC))
-        .extract_keys()
-        .check_network(NETWORK)
-        .load_wallet(&mut db)?;
-    let mut wallet = match wallet_opt {
-        Some(wallet) => wallet,
-        None => Wallet::create(EXTERNAL_DESC, INTERNAL_DESC)
-            .network(NETWORK)
-            .create_wallet(&mut db)?,
-    };
-
-    let address = wallet.next_unused_address(KeychainKind::External);
-    wallet.persist(&mut db)?;
-    println!(
-        "Next unused address: ({}) {}",
-        address.index, address.address
-    );
-
-    let balance = wallet.balance();
-    println!("Wallet balance before syncing: {}", balance.total());
-
-    print!("Syncing...");
-    let client = esplora_client::Builder::new(ESPLORA_URL).build_blocking();
-
-    let request = wallet.start_full_scan().inspect({
-        let mut stdout = std::io::stdout();
-        let mut once = BTreeSet::<KeychainKind>::new();
-        move |keychain, spk_i, _| {
-            if once.insert(keychain) {
-                print!("\nScanning keychain [{:?}] ", keychain);
-            }
-            print!(" {:<3}", spk_i);
-            stdout.flush().expect("must flush")
-        }
-    });
-
-    let update = client.full_scan(request, STOP_GAP, PARALLEL_REQUESTS)?;
-
-    wallet.apply_update(update)?;
-    wallet.persist(&mut db)?;
-    println!();
-
-    let balance = wallet.balance();
-    println!("Wallet balance after syncing: {}", balance.total());
-
-    if balance.total() < SEND_AMOUNT {
-        println!(
-            "Please send at least {} to the receiving address",
-            SEND_AMOUNT
-        );
-        std::process::exit(0);
-    }
-
-    let mut tx_builder = wallet.build_tx();
-    tx_builder
-        .add_recipient(address.script_pubkey(), SEND_AMOUNT)
-        .enable_rbf();
-
-    let mut psbt = tx_builder.finish()?;
-    let finalized = wallet.sign(&mut psbt, SignOptions::default())?;
-    assert!(finalized);
-
-    let tx = psbt.extract_tx()?;
-    client.broadcast(&tx)?;
-    println!("Tx broadcasted! Txid: {}", tx.compute_txid());
-
-    Ok(())
-}
diff --git a/example-crates/wallet_rpc/Cargo.toml b/example-crates/wallet_rpc/Cargo.toml
deleted file mode 100644 (file)
index ffda1d3..0000000
+++ /dev/null
@@ -1,14 +0,0 @@
-[package]
-name = "wallet_rpc"
-version = "0.1.0"
-edition = "2021"
-
-# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
-
-[dependencies]
-bdk_wallet = { path = "../../crates/wallet", features = ["file_store"] }
-bdk_bitcoind_rpc = { path = "../../crates/bitcoind_rpc" }
-
-anyhow = "1"
-clap = { version = "3.2.25", features = ["derive", "env"] }
-ctrlc = "2.0.1"
diff --git a/example-crates/wallet_rpc/README.md b/example-crates/wallet_rpc/README.md
deleted file mode 100644 (file)
index 28eb07b..0000000
+++ /dev/null
@@ -1,45 +0,0 @@
-# Wallet RPC Example 
-
-```
-$ cargo run --bin wallet_rpc -- --help
-
-wallet_rpc 0.1.0
-Bitcoind RPC example using `bdk_wallet::Wallet`
-
-USAGE:
-    wallet_rpc [OPTIONS] <DESCRIPTOR> [CHANGE_DESCRIPTOR]
-
-ARGS:
-    <DESCRIPTOR>           Wallet descriptor [env: DESCRIPTOR=]
-    <CHANGE_DESCRIPTOR>    Wallet change descriptor [env: CHANGE_DESCRIPTOR=]
-
-OPTIONS:
-        --db-path <DB_PATH>
-            Where to store wallet data [env: BDK_DB_PATH=] [default: .bdk_wallet_rpc_example.db]
-
-    -h, --help
-            Print help information
-
-        --network <NETWORK>
-            Bitcoin network to connect to [env: BITCOIN_NETWORK=] [default: testnet]
-
-        --rpc-cookie <RPC_COOKIE>
-            RPC auth cookie file [env: RPC_COOKIE=]
-
-        --rpc-pass <RPC_PASS>
-            RPC auth password [env: RPC_PASS=]
-
-        --rpc-user <RPC_USER>
-            RPC auth username [env: RPC_USER=]
-
-        --start-height <START_HEIGHT>
-            Earliest block height to start sync from [env: START_HEIGHT=] [default: 481824]
-
-        --url <URL>
-            RPC URL [env: RPC_URL=] [default: 127.0.0.1:8332]
-
-    -V, --version
-            Print version information
-
-```
-
diff --git a/example-crates/wallet_rpc/src/main.rs b/example-crates/wallet_rpc/src/main.rs
deleted file mode 100644 (file)
index 204224b..0000000
+++ /dev/null
@@ -1,190 +0,0 @@
-use bdk_bitcoind_rpc::{
-    bitcoincore_rpc::{Auth, Client, RpcApi},
-    Emitter,
-};
-use bdk_wallet::{
-    bitcoin::{Block, Network, Transaction},
-    file_store::Store,
-    KeychainKind, Wallet,
-};
-use clap::{self, Parser};
-use std::{path::PathBuf, sync::mpsc::sync_channel, thread::spawn, time::Instant};
-
-const DB_MAGIC: &str = "bdk-rpc-wallet-example";
-
-/// Bitcoind RPC example using `bdk_wallet::Wallet`.
-///
-/// This syncs the chain block-by-block and prints the current balance, transaction count and UTXO
-/// count.
-#[derive(Parser, Debug)]
-#[clap(author, version, about, long_about = None)]
-#[clap(propagate_version = true)]
-pub struct Args {
-    /// Wallet descriptor
-    #[clap(env = "DESCRIPTOR")]
-    pub descriptor: String,
-    /// Wallet change descriptor
-    #[clap(env = "CHANGE_DESCRIPTOR")]
-    pub change_descriptor: String,
-    /// Earliest block height to start sync from
-    #[clap(env = "START_HEIGHT", long, default_value = "481824")]
-    pub start_height: u32,
-    /// Bitcoin network to connect to
-    #[clap(env = "BITCOIN_NETWORK", long, default_value = "testnet")]
-    pub network: Network,
-    /// Where to store wallet data
-    #[clap(
-        env = "BDK_DB_PATH",
-        long,
-        default_value = ".bdk_wallet_rpc_example.db"
-    )]
-    pub db_path: PathBuf,
-
-    /// RPC URL
-    #[clap(env = "RPC_URL", long, default_value = "127.0.0.1:8332")]
-    pub url: String,
-    /// RPC auth cookie file
-    #[clap(env = "RPC_COOKIE", long)]
-    pub rpc_cookie: Option<PathBuf>,
-    /// RPC auth username
-    #[clap(env = "RPC_USER", long)]
-    pub rpc_user: Option<String>,
-    /// RPC auth password
-    #[clap(env = "RPC_PASS", long)]
-    pub rpc_pass: Option<String>,
-}
-
-impl Args {
-    fn client(&self) -> anyhow::Result<Client> {
-        Ok(Client::new(
-            &self.url,
-            match (&self.rpc_cookie, &self.rpc_user, &self.rpc_pass) {
-                (None, None, None) => Auth::None,
-                (Some(path), _, _) => Auth::CookieFile(path.clone()),
-                (_, Some(user), Some(pass)) => Auth::UserPass(user.clone(), pass.clone()),
-                (_, Some(_), None) => panic!("rpc auth: missing rpc_pass"),
-                (_, None, Some(_)) => panic!("rpc auth: missing rpc_user"),
-            },
-        )?)
-    }
-}
-
-#[derive(Debug)]
-enum Emission {
-    SigTerm,
-    Block(bdk_bitcoind_rpc::BlockEvent<Block>),
-    Mempool(Vec<(Transaction, u64)>),
-}
-
-fn main() -> anyhow::Result<()> {
-    let args = Args::parse();
-
-    let rpc_client = args.client()?;
-    println!(
-        "Connected to Bitcoin Core RPC at {:?}",
-        rpc_client.get_blockchain_info().unwrap()
-    );
-
-    let start_load_wallet = Instant::now();
-    let mut db =
-        Store::<bdk_wallet::ChangeSet>::open_or_create_new(DB_MAGIC.as_bytes(), args.db_path)?;
-    let wallet_opt = Wallet::load()
-        .descriptor(KeychainKind::External, Some(args.descriptor.clone()))
-        .descriptor(KeychainKind::Internal, Some(args.change_descriptor.clone()))
-        .extract_keys()
-        .check_network(args.network)
-        .load_wallet(&mut db)?;
-    let mut wallet = match wallet_opt {
-        Some(wallet) => wallet,
-        None => Wallet::create(args.descriptor, args.change_descriptor)
-            .network(args.network)
-            .create_wallet(&mut db)?,
-    };
-    println!(
-        "Loaded wallet in {}s",
-        start_load_wallet.elapsed().as_secs_f32()
-    );
-
-    let balance = wallet.balance();
-    println!("Wallet balance before syncing: {}", balance.total());
-
-    let wallet_tip = wallet.latest_checkpoint();
-    println!(
-        "Wallet tip: {} at height {}",
-        wallet_tip.hash(),
-        wallet_tip.height()
-    );
-
-    let (sender, receiver) = sync_channel::<Emission>(21);
-
-    let signal_sender = sender.clone();
-    ctrlc::set_handler(move || {
-        signal_sender
-            .send(Emission::SigTerm)
-            .expect("failed to send sigterm")
-    });
-
-    let emitter_tip = wallet_tip.clone();
-    spawn(move || -> Result<(), anyhow::Error> {
-        let mut emitter = Emitter::new(&rpc_client, emitter_tip, args.start_height);
-        while let Some(emission) = emitter.next_block()? {
-            sender.send(Emission::Block(emission))?;
-        }
-        sender.send(Emission::Mempool(emitter.mempool()?))?;
-        Ok(())
-    });
-
-    let mut blocks_received = 0_usize;
-    for emission in receiver {
-        match emission {
-            Emission::SigTerm => {
-                println!("Sigterm received, exiting...");
-                break;
-            }
-            Emission::Block(block_emission) => {
-                blocks_received += 1;
-                let height = block_emission.block_height();
-                let hash = block_emission.block_hash();
-                let connected_to = block_emission.connected_to();
-                let start_apply_block = Instant::now();
-                wallet.apply_block_connected_to(&block_emission.block, height, connected_to)?;
-                wallet.persist(&mut db)?;
-                let elapsed = start_apply_block.elapsed().as_secs_f32();
-                println!(
-                    "Applied block {} at height {} in {}s",
-                    hash, height, elapsed
-                );
-            }
-            Emission::Mempool(mempool_emission) => {
-                let start_apply_mempool = Instant::now();
-                wallet.apply_unconfirmed_txs(mempool_emission);
-                wallet.persist(&mut db)?;
-                println!(
-                    "Applied unconfirmed transactions in {}s",
-                    start_apply_mempool.elapsed().as_secs_f32()
-                );
-                break;
-            }
-        }
-    }
-    let wallet_tip_end = wallet.latest_checkpoint();
-    let balance = wallet.balance();
-    println!(
-        "Synced {} blocks in {}s",
-        blocks_received,
-        start_load_wallet.elapsed().as_secs_f32(),
-    );
-    println!(
-        "Wallet tip is '{}:{}'",
-        wallet_tip_end.height(),
-        wallet_tip_end.hash()
-    );
-    println!("Wallet balance is {}", balance.total());
-    println!(
-        "Wallet has {} transactions and {} utxos",
-        wallet.transactions().count(),
-        wallet.list_unspent().count()
-    );
-
-    Ok(())
-}