]> Untitled Git - bdk/commitdiff
Rename the stub wallet examples
authorLLFourn <lloyd.fourn@gmail.com>
Thu, 2 Mar 2023 05:59:11 +0000 (16:59 +1100)
committerDaniela Brozzoni <danielabrozzoni@protonmail.com>
Thu, 2 Mar 2023 09:56:38 +0000 (10:56 +0100)
23 files changed:
Cargo.toml
example-crates/electrum-wallet/Cargo.toml [deleted file]
example-crates/electrum-wallet/src/main.rs [deleted file]
example-crates/esplora-wallet/Cargo.toml [deleted file]
example-crates/esplora-wallet/src/main.rs [deleted file]
example-crates/keychain_tracker_electrum/.gitignore [new file with mode: 0644]
example-crates/keychain_tracker_electrum/Cargo.toml [new file with mode: 0644]
example-crates/keychain_tracker_electrum/README.md [new file with mode: 0644]
example-crates/keychain_tracker_electrum/src/main.rs [new file with mode: 0644]
example-crates/keychain_tracker_electrum_example/.gitignore [deleted file]
example-crates/keychain_tracker_electrum_example/Cargo.toml [deleted file]
example-crates/keychain_tracker_electrum_example/README.md [deleted file]
example-crates/keychain_tracker_electrum_example/src/main.rs [deleted file]
example-crates/keychain_tracker_esplora/.gitignore [new file with mode: 0644]
example-crates/keychain_tracker_esplora/Cargo.toml [new file with mode: 0644]
example-crates/keychain_tracker_esplora/src/main.rs [new file with mode: 0644]
example-crates/keychain_tracker_esplora_example/.gitignore [deleted file]
example-crates/keychain_tracker_esplora_example/Cargo.toml [deleted file]
example-crates/keychain_tracker_esplora_example/src/main.rs [deleted file]
example-crates/wallet_electrum/Cargo.toml [new file with mode: 0644]
example-crates/wallet_electrum/src/main.rs [new file with mode: 0644]
example-crates/wallet_esplora/Cargo.toml [new file with mode: 0644]
example-crates/wallet_esplora/src/main.rs [new file with mode: 0644]

index 7f97bf6a893df7e0b0011735da4f697184cecd7e..78adeb4506359333d56cfd28473c1e60b74902a7 100644 (file)
@@ -4,11 +4,11 @@ members = [
     "crates/chain",
     "crates/file_store",
     "crates/electrum",
-    "example-crates/esplora-wallet",
-    "example-crates/electrum-wallet",
-    "example-crates/keychain_tracker_electrum_example",
-    "example-crates/keychain_tracker_esplora_example",
+    "example-crates/keychain_tracker_electrum",
+    "example-crates/keychain_tracker_esplora",
     "example-crates/keychain_tracker_example_cli",
+    "example-crates/wallet_electrum",
+    "example-crates/wallet_esplora",
     "nursery/tmp_plan",
     "nursery/coin_select"
 ]
diff --git a/example-crates/electrum-wallet/Cargo.toml b/example-crates/electrum-wallet/Cargo.toml
deleted file mode 100644 (file)
index 5e23005..0000000
+++ /dev/null
@@ -1,7 +0,0 @@
-[package]
-name = "electrum-wallet-example"
-version = "0.1.0"
-edition = "2021"
-
-[dependencies]
-bdk = { path = "../../crates/bdk" }
diff --git a/example-crates/electrum-wallet/src/main.rs b/example-crates/electrum-wallet/src/main.rs
deleted file mode 100644 (file)
index e7a11a9..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-fn main() {
-    println!("Hello, world!");
-}
diff --git a/example-crates/esplora-wallet/Cargo.toml b/example-crates/esplora-wallet/Cargo.toml
deleted file mode 100644 (file)
index 944f09b..0000000
+++ /dev/null
@@ -1,10 +0,0 @@
-[package]
-name = "bdk-esplora-wallet-example"
-version = "0.1.0"
-edition = "2021"
-publish = false
-
-# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
-
-[dependencies]
-bdk = { path = "../../crates/bdk" }
diff --git a/example-crates/esplora-wallet/src/main.rs b/example-crates/esplora-wallet/src/main.rs
deleted file mode 100644 (file)
index e7a11a9..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-fn main() {
-    println!("Hello, world!");
-}
diff --git a/example-crates/keychain_tracker_electrum/.gitignore b/example-crates/keychain_tracker_electrum/.gitignore
new file mode 100644 (file)
index 0000000..ea8c4bf
--- /dev/null
@@ -0,0 +1 @@
+/target
diff --git a/example-crates/keychain_tracker_electrum/Cargo.toml b/example-crates/keychain_tracker_electrum/Cargo.toml
new file mode 100644 (file)
index 0000000..4eceaa7
--- /dev/null
@@ -0,0 +1,9 @@
+[package]
+name = "keychain_tracker_electrum_example"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
+bdk_chain = { path = "../../crates/chain", version = "0.3", features = ["serde"] }
+bdk_electrum = { path = "../../crates/electrum" }
+keychain_tracker_example_cli = { path = "../keychain_tracker_example_cli"}
diff --git a/example-crates/keychain_tracker_electrum/README.md b/example-crates/keychain_tracker_electrum/README.md
new file mode 100644 (file)
index 0000000..b8bdea2
--- /dev/null
@@ -0,0 +1,6 @@
+# Keychain Tracker with electrum
+
+This example shows how you use the `KeychainTracker` from `bdk_chain` to create a simple command
+line wallet.
+
+
diff --git a/example-crates/keychain_tracker_electrum/src/main.rs b/example-crates/keychain_tracker_electrum/src/main.rs
new file mode 100644 (file)
index 0000000..0fe27fd
--- /dev/null
@@ -0,0 +1,248 @@
+use bdk_chain::bitcoin::{Address, OutPoint, Txid};
+use bdk_electrum::bdk_chain::{self, bitcoin::Network, TxHeight};
+use bdk_electrum::{
+    electrum_client::{self, ElectrumApi},
+    ElectrumExt, ElectrumUpdate,
+};
+use keychain_tracker_example_cli::{
+    self as cli,
+    anyhow::{self, Context},
+    clap::{self, Parser, Subcommand},
+};
+use std::{collections::BTreeMap, fmt::Debug, io, io::Write};
+
+#[derive(Subcommand, Debug, Clone)]
+enum ElectrumCommands {
+    /// Scans the addresses in the wallet using esplora API.
+    Scan {
+        /// When a gap this large has been found for a keychain it will stop.
+        #[clap(long, default_value = "5")]
+        stop_gap: usize,
+        #[clap(flatten)]
+        scan_options: ScanOptions,
+    },
+    /// Scans particular addresses using esplora API
+    Sync {
+        /// Scan all the unused addresses
+        #[clap(long)]
+        unused_spks: bool,
+        /// Scan every address that you have derived
+        #[clap(long)]
+        all_spks: bool,
+        /// Scan unspent outpoints for spends or changes to confirmation status of residing tx
+        #[clap(long)]
+        utxos: bool,
+        /// Scan unconfirmed transactions for updates
+        #[clap(long)]
+        unconfirmed: bool,
+        #[clap(flatten)]
+        scan_options: ScanOptions,
+    },
+}
+
+#[derive(Parser, Debug, Clone, PartialEq)]
+pub struct ScanOptions {
+    /// Set batch size for each script_history call to electrum client
+    #[clap(long, default_value = "25")]
+    pub batch_size: usize,
+}
+
+fn main() -> anyhow::Result<()> {
+    let (args, keymap, mut tracker, mut db) = cli::init::<ElectrumCommands, _>()?;
+
+    let electrum_url = match args.network {
+        Network::Bitcoin => "ssl://electrum.blockstream.info:50002",
+        Network::Testnet => "ssl://electrum.blockstream.info:60002",
+        Network::Regtest => "tcp://localhost:60401",
+        Network::Signet => "tcp://signet-electrumx.wakiyamap.dev:50001",
+    };
+    let config = electrum_client::Config::builder()
+        .validate_domain(match args.network {
+            Network::Bitcoin => true,
+            _ => false,
+        })
+        .build();
+
+    let client = electrum_client::Client::from_config(electrum_url, config)?;
+
+    let electrum_cmd = match args.command {
+        cli::Commands::ChainSpecific(electrum_cmd) => electrum_cmd,
+        general_command => {
+            return cli::handle_commands(
+                general_command,
+                |transaction| {
+                    let _txid = client.transaction_broadcast(transaction)?;
+                    Ok(())
+                },
+                &mut tracker,
+                &mut db,
+                args.network,
+                &keymap,
+            )
+        }
+    };
+
+    let response = match electrum_cmd {
+        ElectrumCommands::Scan {
+            stop_gap,
+            scan_options: scan_option,
+        } => {
+            let (spk_iterators, local_chain) = {
+                // Get a short lock on the tracker to get the spks iterators
+                // and local chain state
+                let tracker = &*tracker.lock().unwrap();
+                let spk_iterators = tracker
+                    .txout_index
+                    .spks_of_all_keychains()
+                    .into_iter()
+                    .map(|(keychain, iter)| {
+                        let mut first = true;
+                        let spk_iter = iter.inspect(move |(i, _)| {
+                            if first {
+                                eprint!("\nscanning {}: ", keychain);
+                                first = false;
+                            }
+
+                            eprint!("{} ", i);
+                            let _ = io::stdout().flush();
+                        });
+                        (keychain, spk_iter)
+                    })
+                    .collect::<BTreeMap<_, _>>();
+                let local_chain = tracker.chain().checkpoints().clone();
+                (spk_iterators, local_chain)
+            };
+
+            // we scan the spks **without** a lock on the tracker
+            client.scan(
+                &local_chain,
+                spk_iterators,
+                core::iter::empty(),
+                core::iter::empty(),
+                stop_gap,
+                scan_option.batch_size,
+            )?
+        }
+        ElectrumCommands::Sync {
+            mut unused_spks,
+            mut utxos,
+            mut unconfirmed,
+            all_spks,
+            scan_options,
+        } => {
+            // Get a short lock on the tracker to get the spks we're interested in
+            let tracker = tracker.lock().unwrap();
+
+            if !(all_spks || unused_spks || utxos || unconfirmed) {
+                unused_spks = true;
+                unconfirmed = true;
+                utxos = true;
+            } else if all_spks {
+                unused_spks = false;
+            }
+
+            let mut spks: Box<dyn Iterator<Item = bdk_chain::bitcoin::Script>> =
+                Box::new(core::iter::empty());
+            if all_spks {
+                let all_spks = tracker
+                    .txout_index
+                    .all_spks()
+                    .iter()
+                    .map(|(k, v)| (k.clone(), v.clone()))
+                    .collect::<Vec<_>>();
+                spks = Box::new(spks.chain(all_spks.into_iter().map(|(index, script)| {
+                    eprintln!("scanning {:?}", index);
+                    script
+                })));
+            }
+            if unused_spks {
+                let unused_spks = tracker
+                    .txout_index
+                    .unused_spks(..)
+                    .map(|(k, v)| (k.clone(), v.clone()))
+                    .collect::<Vec<_>>();
+                spks = Box::new(spks.chain(unused_spks.into_iter().map(|(index, script)| {
+                    eprintln!(
+                        "Checking if address {} {:?} has been used",
+                        Address::from_script(&script, args.network).unwrap(),
+                        index
+                    );
+
+                    script
+                })));
+            }
+
+            let mut outpoints: Box<dyn Iterator<Item = OutPoint>> = Box::new(core::iter::empty());
+
+            if utxos {
+                let utxos = tracker
+                    .full_utxos()
+                    .map(|(_, utxo)| utxo)
+                    .collect::<Vec<_>>();
+                outpoints = Box::new(
+                    utxos
+                        .into_iter()
+                        .inspect(|utxo| {
+                            eprintln!(
+                                "Checking if outpoint {} (value: {}) has been spent",
+                                utxo.outpoint, utxo.txout.value
+                            );
+                        })
+                        .map(|utxo| utxo.outpoint),
+                );
+            };
+
+            let mut txids: Box<dyn Iterator<Item = Txid>> = Box::new(core::iter::empty());
+
+            if unconfirmed {
+                let unconfirmed_txids = tracker
+                    .chain()
+                    .range_txids_by_height(TxHeight::Unconfirmed..)
+                    .map(|(_, txid)| *txid)
+                    .collect::<Vec<_>>();
+
+                txids = Box::new(unconfirmed_txids.into_iter().inspect(|txid| {
+                    eprintln!("Checking if {} is confirmed yet", txid);
+                }));
+            }
+
+            let local_chain = tracker.chain().checkpoints().clone();
+            // drop lock on tracker
+            drop(tracker);
+
+            // we scan the spks **without** a lock on the tracker
+            ElectrumUpdate {
+                chain_update: client
+                    .scan_without_keychain(
+                        &local_chain,
+                        spks,
+                        txids,
+                        outpoints,
+                        scan_options.batch_size,
+                    )
+                    .context("scanning the blockchain")?,
+                ..Default::default()
+            }
+        }
+    };
+
+    let missing_txids = response.missing_full_txs(&*tracker.lock().unwrap());
+
+    // fetch the missing full transactions **without** a lock on the tracker
+    let new_txs = client
+        .batch_transaction_get(missing_txids)
+        .context("fetching full transactions")?;
+
+    {
+        // Get a final short lock to apply the changes
+        let mut tracker = tracker.lock().unwrap();
+        let changeset = {
+            let scan = response.into_keychain_scan(new_txs, &*tracker)?;
+            tracker.determine_changeset(&scan)?
+        };
+        db.lock().unwrap().append_changeset(&changeset)?;
+        tracker.apply_changeset(changeset);
+    };
+
+    Ok(())
+}
diff --git a/example-crates/keychain_tracker_electrum_example/.gitignore b/example-crates/keychain_tracker_electrum_example/.gitignore
deleted file mode 100644 (file)
index ea8c4bf..0000000
+++ /dev/null
@@ -1 +0,0 @@
-/target
diff --git a/example-crates/keychain_tracker_electrum_example/Cargo.toml b/example-crates/keychain_tracker_electrum_example/Cargo.toml
deleted file mode 100644 (file)
index 4eceaa7..0000000
+++ /dev/null
@@ -1,9 +0,0 @@
-[package]
-name = "keychain_tracker_electrum_example"
-version = "0.1.0"
-edition = "2021"
-
-[dependencies]
-bdk_chain = { path = "../../crates/chain", version = "0.3", features = ["serde"] }
-bdk_electrum = { path = "../../crates/electrum" }
-keychain_tracker_example_cli = { path = "../keychain_tracker_example_cli"}
diff --git a/example-crates/keychain_tracker_electrum_example/README.md b/example-crates/keychain_tracker_electrum_example/README.md
deleted file mode 100644 (file)
index b8bdea2..0000000
+++ /dev/null
@@ -1,6 +0,0 @@
-# Keychain Tracker with electrum
-
-This example shows how you use the `KeychainTracker` from `bdk_chain` to create a simple command
-line wallet.
-
-
diff --git a/example-crates/keychain_tracker_electrum_example/src/main.rs b/example-crates/keychain_tracker_electrum_example/src/main.rs
deleted file mode 100644 (file)
index 0fe27fd..0000000
+++ /dev/null
@@ -1,248 +0,0 @@
-use bdk_chain::bitcoin::{Address, OutPoint, Txid};
-use bdk_electrum::bdk_chain::{self, bitcoin::Network, TxHeight};
-use bdk_electrum::{
-    electrum_client::{self, ElectrumApi},
-    ElectrumExt, ElectrumUpdate,
-};
-use keychain_tracker_example_cli::{
-    self as cli,
-    anyhow::{self, Context},
-    clap::{self, Parser, Subcommand},
-};
-use std::{collections::BTreeMap, fmt::Debug, io, io::Write};
-
-#[derive(Subcommand, Debug, Clone)]
-enum ElectrumCommands {
-    /// Scans the addresses in the wallet using esplora API.
-    Scan {
-        /// When a gap this large has been found for a keychain it will stop.
-        #[clap(long, default_value = "5")]
-        stop_gap: usize,
-        #[clap(flatten)]
-        scan_options: ScanOptions,
-    },
-    /// Scans particular addresses using esplora API
-    Sync {
-        /// Scan all the unused addresses
-        #[clap(long)]
-        unused_spks: bool,
-        /// Scan every address that you have derived
-        #[clap(long)]
-        all_spks: bool,
-        /// Scan unspent outpoints for spends or changes to confirmation status of residing tx
-        #[clap(long)]
-        utxos: bool,
-        /// Scan unconfirmed transactions for updates
-        #[clap(long)]
-        unconfirmed: bool,
-        #[clap(flatten)]
-        scan_options: ScanOptions,
-    },
-}
-
-#[derive(Parser, Debug, Clone, PartialEq)]
-pub struct ScanOptions {
-    /// Set batch size for each script_history call to electrum client
-    #[clap(long, default_value = "25")]
-    pub batch_size: usize,
-}
-
-fn main() -> anyhow::Result<()> {
-    let (args, keymap, mut tracker, mut db) = cli::init::<ElectrumCommands, _>()?;
-
-    let electrum_url = match args.network {
-        Network::Bitcoin => "ssl://electrum.blockstream.info:50002",
-        Network::Testnet => "ssl://electrum.blockstream.info:60002",
-        Network::Regtest => "tcp://localhost:60401",
-        Network::Signet => "tcp://signet-electrumx.wakiyamap.dev:50001",
-    };
-    let config = electrum_client::Config::builder()
-        .validate_domain(match args.network {
-            Network::Bitcoin => true,
-            _ => false,
-        })
-        .build();
-
-    let client = electrum_client::Client::from_config(electrum_url, config)?;
-
-    let electrum_cmd = match args.command {
-        cli::Commands::ChainSpecific(electrum_cmd) => electrum_cmd,
-        general_command => {
-            return cli::handle_commands(
-                general_command,
-                |transaction| {
-                    let _txid = client.transaction_broadcast(transaction)?;
-                    Ok(())
-                },
-                &mut tracker,
-                &mut db,
-                args.network,
-                &keymap,
-            )
-        }
-    };
-
-    let response = match electrum_cmd {
-        ElectrumCommands::Scan {
-            stop_gap,
-            scan_options: scan_option,
-        } => {
-            let (spk_iterators, local_chain) = {
-                // Get a short lock on the tracker to get the spks iterators
-                // and local chain state
-                let tracker = &*tracker.lock().unwrap();
-                let spk_iterators = tracker
-                    .txout_index
-                    .spks_of_all_keychains()
-                    .into_iter()
-                    .map(|(keychain, iter)| {
-                        let mut first = true;
-                        let spk_iter = iter.inspect(move |(i, _)| {
-                            if first {
-                                eprint!("\nscanning {}: ", keychain);
-                                first = false;
-                            }
-
-                            eprint!("{} ", i);
-                            let _ = io::stdout().flush();
-                        });
-                        (keychain, spk_iter)
-                    })
-                    .collect::<BTreeMap<_, _>>();
-                let local_chain = tracker.chain().checkpoints().clone();
-                (spk_iterators, local_chain)
-            };
-
-            // we scan the spks **without** a lock on the tracker
-            client.scan(
-                &local_chain,
-                spk_iterators,
-                core::iter::empty(),
-                core::iter::empty(),
-                stop_gap,
-                scan_option.batch_size,
-            )?
-        }
-        ElectrumCommands::Sync {
-            mut unused_spks,
-            mut utxos,
-            mut unconfirmed,
-            all_spks,
-            scan_options,
-        } => {
-            // Get a short lock on the tracker to get the spks we're interested in
-            let tracker = tracker.lock().unwrap();
-
-            if !(all_spks || unused_spks || utxos || unconfirmed) {
-                unused_spks = true;
-                unconfirmed = true;
-                utxos = true;
-            } else if all_spks {
-                unused_spks = false;
-            }
-
-            let mut spks: Box<dyn Iterator<Item = bdk_chain::bitcoin::Script>> =
-                Box::new(core::iter::empty());
-            if all_spks {
-                let all_spks = tracker
-                    .txout_index
-                    .all_spks()
-                    .iter()
-                    .map(|(k, v)| (k.clone(), v.clone()))
-                    .collect::<Vec<_>>();
-                spks = Box::new(spks.chain(all_spks.into_iter().map(|(index, script)| {
-                    eprintln!("scanning {:?}", index);
-                    script
-                })));
-            }
-            if unused_spks {
-                let unused_spks = tracker
-                    .txout_index
-                    .unused_spks(..)
-                    .map(|(k, v)| (k.clone(), v.clone()))
-                    .collect::<Vec<_>>();
-                spks = Box::new(spks.chain(unused_spks.into_iter().map(|(index, script)| {
-                    eprintln!(
-                        "Checking if address {} {:?} has been used",
-                        Address::from_script(&script, args.network).unwrap(),
-                        index
-                    );
-
-                    script
-                })));
-            }
-
-            let mut outpoints: Box<dyn Iterator<Item = OutPoint>> = Box::new(core::iter::empty());
-
-            if utxos {
-                let utxos = tracker
-                    .full_utxos()
-                    .map(|(_, utxo)| utxo)
-                    .collect::<Vec<_>>();
-                outpoints = Box::new(
-                    utxos
-                        .into_iter()
-                        .inspect(|utxo| {
-                            eprintln!(
-                                "Checking if outpoint {} (value: {}) has been spent",
-                                utxo.outpoint, utxo.txout.value
-                            );
-                        })
-                        .map(|utxo| utxo.outpoint),
-                );
-            };
-
-            let mut txids: Box<dyn Iterator<Item = Txid>> = Box::new(core::iter::empty());
-
-            if unconfirmed {
-                let unconfirmed_txids = tracker
-                    .chain()
-                    .range_txids_by_height(TxHeight::Unconfirmed..)
-                    .map(|(_, txid)| *txid)
-                    .collect::<Vec<_>>();
-
-                txids = Box::new(unconfirmed_txids.into_iter().inspect(|txid| {
-                    eprintln!("Checking if {} is confirmed yet", txid);
-                }));
-            }
-
-            let local_chain = tracker.chain().checkpoints().clone();
-            // drop lock on tracker
-            drop(tracker);
-
-            // we scan the spks **without** a lock on the tracker
-            ElectrumUpdate {
-                chain_update: client
-                    .scan_without_keychain(
-                        &local_chain,
-                        spks,
-                        txids,
-                        outpoints,
-                        scan_options.batch_size,
-                    )
-                    .context("scanning the blockchain")?,
-                ..Default::default()
-            }
-        }
-    };
-
-    let missing_txids = response.missing_full_txs(&*tracker.lock().unwrap());
-
-    // fetch the missing full transactions **without** a lock on the tracker
-    let new_txs = client
-        .batch_transaction_get(missing_txids)
-        .context("fetching full transactions")?;
-
-    {
-        // Get a final short lock to apply the changes
-        let mut tracker = tracker.lock().unwrap();
-        let changeset = {
-            let scan = response.into_keychain_scan(new_txs, &*tracker)?;
-            tracker.determine_changeset(&scan)?
-        };
-        db.lock().unwrap().append_changeset(&changeset)?;
-        tracker.apply_changeset(changeset);
-    };
-
-    Ok(())
-}
diff --git a/example-crates/keychain_tracker_esplora/.gitignore b/example-crates/keychain_tracker_esplora/.gitignore
new file mode 100644 (file)
index 0000000..8359723
--- /dev/null
@@ -0,0 +1,3 @@
+/target
+Cargo.lock
+.bdk_example_db
diff --git a/example-crates/keychain_tracker_esplora/Cargo.toml b/example-crates/keychain_tracker_esplora/Cargo.toml
new file mode 100644 (file)
index 0000000..57e9d9c
--- /dev/null
@@ -0,0 +1,11 @@
+[package]
+name = "keychain_tracker_esplora_example"
+version = "0.1.0"
+edition = "2021"
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+bdk_chain = { path = "../../crates/chain", version = "0.3", features = ["serde", "miniscript"] }
+bdk_esplora = { path = "../../crates/esplora" }
+keychain_tracker_example_cli = { path = "../keychain_tracker_example_cli" }
diff --git a/example-crates/keychain_tracker_esplora/src/main.rs b/example-crates/keychain_tracker_esplora/src/main.rs
new file mode 100644 (file)
index 0000000..fba4a3b
--- /dev/null
@@ -0,0 +1,241 @@
+use bdk_chain::bitcoin::{Address, OutPoint, Txid};
+use bdk_chain::{bitcoin::Network, TxHeight};
+use bdk_esplora::esplora_client;
+use bdk_esplora::EsploraExt;
+
+use std::io::{self, Write};
+
+use keychain_tracker_example_cli::{
+    self as cli,
+    anyhow::{self, Context},
+    clap::{self, Parser, Subcommand},
+};
+
+#[derive(Subcommand, Debug, Clone)]
+enum EsploraCommands {
+    /// Scans the addresses in the wallet using esplora API.
+    Scan {
+        /// When a gap this large has been found for a keychain it will stop.
+        #[clap(long, default_value = "5")]
+        stop_gap: usize,
+
+        #[clap(flatten)]
+        scan_options: ScanOptions,
+    },
+    /// Scans particular addresses using esplora API
+    Sync {
+        /// Scan all the unused addresses
+        #[clap(long)]
+        unused_spks: bool,
+        /// Scan every address that you have derived
+        #[clap(long)]
+        all_spks: bool,
+        /// Scan unspent outpoints for spends or changes to confirmation status of residing tx
+        #[clap(long)]
+        utxos: bool,
+        /// Scan unconfirmed transactions for updates
+        #[clap(long)]
+        unconfirmed: bool,
+
+        #[clap(flatten)]
+        scan_options: ScanOptions,
+    },
+}
+
+#[derive(Parser, Debug, Clone, PartialEq)]
+pub struct ScanOptions {
+    #[clap(long, default_value = "5")]
+    pub parallel_requests: usize,
+}
+
+fn main() -> anyhow::Result<()> {
+    let (args, keymap, keychain_tracker, db) = cli::init::<EsploraCommands, _>()?;
+    let esplora_url = match args.network {
+        Network::Bitcoin => "https://mempool.space/api",
+        Network::Testnet => "https://mempool.space/testnet/api",
+        Network::Regtest => "http://localhost:3002",
+        Network::Signet => "https://mempool.space/signet/api",
+    };
+
+    let client = esplora_client::Builder::new(esplora_url).build_blocking()?;
+
+    let esplora_cmd = match args.command {
+        cli::Commands::ChainSpecific(esplora_cmd) => esplora_cmd,
+        general_command => {
+            return cli::handle_commands(
+                general_command,
+                |transaction| Ok(client.broadcast(transaction)?),
+                &keychain_tracker,
+                &db,
+                args.network,
+                &keymap,
+            )
+        }
+    };
+
+    match esplora_cmd {
+        EsploraCommands::Scan {
+            stop_gap,
+            scan_options,
+        } => {
+            let (spk_iterators, local_chain) = {
+                // Get a short lock on the tracker to get the spks iterators
+                // and local chain state
+                let tracker = &*keychain_tracker.lock().unwrap();
+                let spk_iterators = tracker
+                    .txout_index
+                    .spks_of_all_keychains()
+                    .into_iter()
+                    .map(|(keychain, iter)| {
+                        let mut first = true;
+                        (
+                            keychain,
+                            iter.inspect(move |(i, _)| {
+                                if first {
+                                    eprint!("\nscanning {}: ", keychain);
+                                    first = false;
+                                }
+
+                                eprint!("{} ", i);
+                                let _ = io::stdout().flush();
+                            }),
+                        )
+                    })
+                    .collect();
+
+                let local_chain = tracker.chain().checkpoints().clone();
+                (spk_iterators, local_chain)
+            };
+
+            // we scan the iterators **without** a lock on the tracker
+            let wallet_scan = client
+                .scan(
+                    &local_chain,
+                    spk_iterators,
+                    core::iter::empty(),
+                    core::iter::empty(),
+                    stop_gap,
+                    scan_options.parallel_requests,
+                )
+                .context("scanning the blockchain")?;
+            eprintln!();
+
+            {
+                // we take a short lock to apply results to tracker and db
+                let tracker = &mut *keychain_tracker.lock().unwrap();
+                let db = &mut *db.lock().unwrap();
+                let changeset = tracker.apply_update(wallet_scan)?;
+                db.append_changeset(&changeset)?;
+            }
+        }
+        EsploraCommands::Sync {
+            mut unused_spks,
+            mut utxos,
+            mut unconfirmed,
+            all_spks,
+            scan_options,
+        } => {
+            // Get a short lock on the tracker to get the spks we're interested in
+            let tracker = keychain_tracker.lock().unwrap();
+
+            if !(all_spks || unused_spks || utxos || unconfirmed) {
+                unused_spks = true;
+                unconfirmed = true;
+                utxos = true;
+            } else if all_spks {
+                unused_spks = false;
+            }
+
+            let mut spks: Box<dyn Iterator<Item = bdk_chain::bitcoin::Script>> =
+                Box::new(core::iter::empty());
+            if all_spks {
+                let all_spks = tracker
+                    .txout_index
+                    .all_spks()
+                    .iter()
+                    .map(|(k, v)| (k.clone(), v.clone()))
+                    .collect::<Vec<_>>();
+                spks = Box::new(spks.chain(all_spks.into_iter().map(|(index, script)| {
+                    eprintln!("scanning {:?}", index);
+                    script
+                })));
+            }
+            if unused_spks {
+                let unused_spks = tracker
+                    .txout_index
+                    .unused_spks(..)
+                    .map(|(k, v)| (k.clone(), v.clone()))
+                    .collect::<Vec<_>>();
+                spks = Box::new(spks.chain(unused_spks.into_iter().map(|(index, script)| {
+                    eprintln!(
+                        "Checking if address {} {:?} has been used",
+                        Address::from_script(&script, args.network).unwrap(),
+                        index
+                    );
+
+                    script
+                })));
+            }
+
+            let mut outpoints: Box<dyn Iterator<Item = OutPoint>> = Box::new(core::iter::empty());
+
+            if utxos {
+                let utxos = tracker
+                    .full_utxos()
+                    .map(|(_, utxo)| utxo)
+                    .collect::<Vec<_>>();
+                outpoints = Box::new(
+                    utxos
+                        .into_iter()
+                        .inspect(|utxo| {
+                            eprintln!(
+                                "Checking if outpoint {} (value: {}) has been spent",
+                                utxo.outpoint, utxo.txout.value
+                            );
+                        })
+                        .map(|utxo| utxo.outpoint),
+                );
+            };
+
+            let mut txids: Box<dyn Iterator<Item = Txid>> = Box::new(core::iter::empty());
+
+            if unconfirmed {
+                let unconfirmed_txids = tracker
+                    .chain()
+                    .range_txids_by_height(TxHeight::Unconfirmed..)
+                    .map(|(_, txid)| *txid)
+                    .collect::<Vec<_>>();
+
+                txids = Box::new(unconfirmed_txids.into_iter().inspect(|txid| {
+                    eprintln!("Checking if {} is confirmed yet", txid);
+                }));
+            }
+
+            let local_chain = tracker.chain().checkpoints().clone();
+
+            // drop lock on tracker
+            drop(tracker);
+
+            // we scan the desired spks **without** a lock on the tracker
+            let scan = client
+                .scan_without_keychain(
+                    &local_chain,
+                    spks,
+                    txids,
+                    outpoints,
+                    scan_options.parallel_requests,
+                )
+                .context("scanning the blockchain")?;
+
+            {
+                // we take a short lock to apply the results to the tracker and db
+                let tracker = &mut *keychain_tracker.lock().unwrap();
+                let changeset = tracker.apply_update(scan.into())?;
+                let db = &mut *db.lock().unwrap();
+                db.append_changeset(&changeset)?;
+            }
+        }
+    }
+
+    Ok(())
+}
diff --git a/example-crates/keychain_tracker_esplora_example/.gitignore b/example-crates/keychain_tracker_esplora_example/.gitignore
deleted file mode 100644 (file)
index 8359723..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-/target
-Cargo.lock
-.bdk_example_db
diff --git a/example-crates/keychain_tracker_esplora_example/Cargo.toml b/example-crates/keychain_tracker_esplora_example/Cargo.toml
deleted file mode 100644 (file)
index 57e9d9c..0000000
+++ /dev/null
@@ -1,11 +0,0 @@
-[package]
-name = "keychain_tracker_esplora_example"
-version = "0.1.0"
-edition = "2021"
-
-# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
-
-[dependencies]
-bdk_chain = { path = "../../crates/chain", version = "0.3", features = ["serde", "miniscript"] }
-bdk_esplora = { path = "../../crates/esplora" }
-keychain_tracker_example_cli = { path = "../keychain_tracker_example_cli" }
diff --git a/example-crates/keychain_tracker_esplora_example/src/main.rs b/example-crates/keychain_tracker_esplora_example/src/main.rs
deleted file mode 100644 (file)
index fba4a3b..0000000
+++ /dev/null
@@ -1,241 +0,0 @@
-use bdk_chain::bitcoin::{Address, OutPoint, Txid};
-use bdk_chain::{bitcoin::Network, TxHeight};
-use bdk_esplora::esplora_client;
-use bdk_esplora::EsploraExt;
-
-use std::io::{self, Write};
-
-use keychain_tracker_example_cli::{
-    self as cli,
-    anyhow::{self, Context},
-    clap::{self, Parser, Subcommand},
-};
-
-#[derive(Subcommand, Debug, Clone)]
-enum EsploraCommands {
-    /// Scans the addresses in the wallet using esplora API.
-    Scan {
-        /// When a gap this large has been found for a keychain it will stop.
-        #[clap(long, default_value = "5")]
-        stop_gap: usize,
-
-        #[clap(flatten)]
-        scan_options: ScanOptions,
-    },
-    /// Scans particular addresses using esplora API
-    Sync {
-        /// Scan all the unused addresses
-        #[clap(long)]
-        unused_spks: bool,
-        /// Scan every address that you have derived
-        #[clap(long)]
-        all_spks: bool,
-        /// Scan unspent outpoints for spends or changes to confirmation status of residing tx
-        #[clap(long)]
-        utxos: bool,
-        /// Scan unconfirmed transactions for updates
-        #[clap(long)]
-        unconfirmed: bool,
-
-        #[clap(flatten)]
-        scan_options: ScanOptions,
-    },
-}
-
-#[derive(Parser, Debug, Clone, PartialEq)]
-pub struct ScanOptions {
-    #[clap(long, default_value = "5")]
-    pub parallel_requests: usize,
-}
-
-fn main() -> anyhow::Result<()> {
-    let (args, keymap, keychain_tracker, db) = cli::init::<EsploraCommands, _>()?;
-    let esplora_url = match args.network {
-        Network::Bitcoin => "https://mempool.space/api",
-        Network::Testnet => "https://mempool.space/testnet/api",
-        Network::Regtest => "http://localhost:3002",
-        Network::Signet => "https://mempool.space/signet/api",
-    };
-
-    let client = esplora_client::Builder::new(esplora_url).build_blocking()?;
-
-    let esplora_cmd = match args.command {
-        cli::Commands::ChainSpecific(esplora_cmd) => esplora_cmd,
-        general_command => {
-            return cli::handle_commands(
-                general_command,
-                |transaction| Ok(client.broadcast(transaction)?),
-                &keychain_tracker,
-                &db,
-                args.network,
-                &keymap,
-            )
-        }
-    };
-
-    match esplora_cmd {
-        EsploraCommands::Scan {
-            stop_gap,
-            scan_options,
-        } => {
-            let (spk_iterators, local_chain) = {
-                // Get a short lock on the tracker to get the spks iterators
-                // and local chain state
-                let tracker = &*keychain_tracker.lock().unwrap();
-                let spk_iterators = tracker
-                    .txout_index
-                    .spks_of_all_keychains()
-                    .into_iter()
-                    .map(|(keychain, iter)| {
-                        let mut first = true;
-                        (
-                            keychain,
-                            iter.inspect(move |(i, _)| {
-                                if first {
-                                    eprint!("\nscanning {}: ", keychain);
-                                    first = false;
-                                }
-
-                                eprint!("{} ", i);
-                                let _ = io::stdout().flush();
-                            }),
-                        )
-                    })
-                    .collect();
-
-                let local_chain = tracker.chain().checkpoints().clone();
-                (spk_iterators, local_chain)
-            };
-
-            // we scan the iterators **without** a lock on the tracker
-            let wallet_scan = client
-                .scan(
-                    &local_chain,
-                    spk_iterators,
-                    core::iter::empty(),
-                    core::iter::empty(),
-                    stop_gap,
-                    scan_options.parallel_requests,
-                )
-                .context("scanning the blockchain")?;
-            eprintln!();
-
-            {
-                // we take a short lock to apply results to tracker and db
-                let tracker = &mut *keychain_tracker.lock().unwrap();
-                let db = &mut *db.lock().unwrap();
-                let changeset = tracker.apply_update(wallet_scan)?;
-                db.append_changeset(&changeset)?;
-            }
-        }
-        EsploraCommands::Sync {
-            mut unused_spks,
-            mut utxos,
-            mut unconfirmed,
-            all_spks,
-            scan_options,
-        } => {
-            // Get a short lock on the tracker to get the spks we're interested in
-            let tracker = keychain_tracker.lock().unwrap();
-
-            if !(all_spks || unused_spks || utxos || unconfirmed) {
-                unused_spks = true;
-                unconfirmed = true;
-                utxos = true;
-            } else if all_spks {
-                unused_spks = false;
-            }
-
-            let mut spks: Box<dyn Iterator<Item = bdk_chain::bitcoin::Script>> =
-                Box::new(core::iter::empty());
-            if all_spks {
-                let all_spks = tracker
-                    .txout_index
-                    .all_spks()
-                    .iter()
-                    .map(|(k, v)| (k.clone(), v.clone()))
-                    .collect::<Vec<_>>();
-                spks = Box::new(spks.chain(all_spks.into_iter().map(|(index, script)| {
-                    eprintln!("scanning {:?}", index);
-                    script
-                })));
-            }
-            if unused_spks {
-                let unused_spks = tracker
-                    .txout_index
-                    .unused_spks(..)
-                    .map(|(k, v)| (k.clone(), v.clone()))
-                    .collect::<Vec<_>>();
-                spks = Box::new(spks.chain(unused_spks.into_iter().map(|(index, script)| {
-                    eprintln!(
-                        "Checking if address {} {:?} has been used",
-                        Address::from_script(&script, args.network).unwrap(),
-                        index
-                    );
-
-                    script
-                })));
-            }
-
-            let mut outpoints: Box<dyn Iterator<Item = OutPoint>> = Box::new(core::iter::empty());
-
-            if utxos {
-                let utxos = tracker
-                    .full_utxos()
-                    .map(|(_, utxo)| utxo)
-                    .collect::<Vec<_>>();
-                outpoints = Box::new(
-                    utxos
-                        .into_iter()
-                        .inspect(|utxo| {
-                            eprintln!(
-                                "Checking if outpoint {} (value: {}) has been spent",
-                                utxo.outpoint, utxo.txout.value
-                            );
-                        })
-                        .map(|utxo| utxo.outpoint),
-                );
-            };
-
-            let mut txids: Box<dyn Iterator<Item = Txid>> = Box::new(core::iter::empty());
-
-            if unconfirmed {
-                let unconfirmed_txids = tracker
-                    .chain()
-                    .range_txids_by_height(TxHeight::Unconfirmed..)
-                    .map(|(_, txid)| *txid)
-                    .collect::<Vec<_>>();
-
-                txids = Box::new(unconfirmed_txids.into_iter().inspect(|txid| {
-                    eprintln!("Checking if {} is confirmed yet", txid);
-                }));
-            }
-
-            let local_chain = tracker.chain().checkpoints().clone();
-
-            // drop lock on tracker
-            drop(tracker);
-
-            // we scan the desired spks **without** a lock on the tracker
-            let scan = client
-                .scan_without_keychain(
-                    &local_chain,
-                    spks,
-                    txids,
-                    outpoints,
-                    scan_options.parallel_requests,
-                )
-                .context("scanning the blockchain")?;
-
-            {
-                // we take a short lock to apply the results to the tracker and db
-                let tracker = &mut *keychain_tracker.lock().unwrap();
-                let changeset = tracker.apply_update(scan.into())?;
-                let db = &mut *db.lock().unwrap();
-                db.append_changeset(&changeset)?;
-            }
-        }
-    }
-
-    Ok(())
-}
diff --git a/example-crates/wallet_electrum/Cargo.toml b/example-crates/wallet_electrum/Cargo.toml
new file mode 100644 (file)
index 0000000..0415d22
--- /dev/null
@@ -0,0 +1,7 @@
+[package]
+name = "wallet_electrum_example"
+version = "0.1.0"
+edition = "2021"
+
+[dependencies]
+bdk = { path = "../../crates/bdk" }
diff --git a/example-crates/wallet_electrum/src/main.rs b/example-crates/wallet_electrum/src/main.rs
new file mode 100644 (file)
index 0000000..e7a11a9
--- /dev/null
@@ -0,0 +1,3 @@
+fn main() {
+    println!("Hello, world!");
+}
diff --git a/example-crates/wallet_esplora/Cargo.toml b/example-crates/wallet_esplora/Cargo.toml
new file mode 100644 (file)
index 0000000..944f09b
--- /dev/null
@@ -0,0 +1,10 @@
+[package]
+name = "bdk-esplora-wallet-example"
+version = "0.1.0"
+edition = "2021"
+publish = false
+
+# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
+
+[dependencies]
+bdk = { path = "../../crates/bdk" }
diff --git a/example-crates/wallet_esplora/src/main.rs b/example-crates/wallet_esplora/src/main.rs
new file mode 100644 (file)
index 0000000..e7a11a9
--- /dev/null
@@ -0,0 +1,3 @@
+fn main() {
+    println!("Hello, world!");
+}