pub use bdk_chain::keychain::Balance;
use bdk_chain::{
indexed_tx_graph,
- keychain::{KeychainTxOutIndex, WalletChangeSet},
+ keychain::{self, KeychainTxOutIndex},
local_chain::{self, CannotConnectError, CheckPoint, CheckPointIter, LocalChain},
tx_graph::{CanonicalTx, TxGraph},
- Append, BlockId, ChainPosition, ConfirmationTime, ConfirmationTimeAnchor, FullTxOut,
+ Anchor, Append, BlockId, ChainPosition, ConfirmationTime, ConfirmationTimeAnchor, FullTxOut,
IndexedTxGraph, Persist, PersistBackend,
};
use bitcoin::consensus::encode::serialize;
}
}
+/// A structure that records the corresponding changes as result of applying an [`WalletUpdate`].
+#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
+pub struct WalletChangeSet<K, A> {
+ /// Changes to the [`LocalChain`].
+ ///
+ /// [`LocalChain`]: local_chain::LocalChain
+ pub chain: local_chain::ChangeSet,
+
+ /// ChangeSet to [`IndexedTxGraph`].
+ ///
+ /// [`IndexedTxGraph`]: bdk_chain::indexed_tx_graph::IndexedTxGraph
+ #[serde(bound(
+ deserialize = "K: Ord + serde::Deserialize<'de>, A: Ord + serde::Deserialize<'de>",
+ serialize = "K: Ord + serde::Serialize, A: Ord + serde::Serialize",
+ ))]
+ pub index_tx_graph: indexed_tx_graph::ChangeSet<A, keychain::ChangeSet<K>>,
+}
+
+impl<K, A> Default for WalletChangeSet<K, A> {
+ fn default() -> Self {
+ Self {
+ chain: Default::default(),
+ index_tx_graph: Default::default(),
+ }
+ }
+}
+
+impl<K: Ord, A: Anchor> Append for WalletChangeSet<K, A> {
+ fn append(&mut self, other: Self) {
+ Append::append(&mut self.chain, other.chain);
+ Append::append(&mut self.index_tx_graph, other.index_tx_graph);
+ }
+
+ fn is_empty(&self) -> bool {
+ self.chain.is_empty() && self.index_tx_graph.is_empty()
+ }
+}
+
+impl<K, A> From<local_chain::ChangeSet> for WalletChangeSet<K, A> {
+ fn from(chain: local_chain::ChangeSet) -> Self {
+ Self {
+ chain,
+ ..Default::default()
+ }
+ }
+}
+
+impl<K, A> From<indexed_tx_graph::ChangeSet<A, keychain::ChangeSet<K>>> for WalletChangeSet<K, A> {
+ fn from(index_tx_graph: indexed_tx_graph::ChangeSet<A, keychain::ChangeSet<K>>) -> Self {
+ Self {
+ index_tx_graph,
+ ..Default::default()
+ }
+ }
+}
+
/// The update to a [`Wallet`] used in [`Wallet::apply_update`]. This is usually returned from blockchain data sources.
pub type Update = WalletUpdate<KeychainKind, ConfirmationTimeAnchor>;
let changeset = db.load_from_persistence().map_err(NewError::Persist)?;
chain.apply_changeset(&changeset.chain);
- indexed_graph.apply_changeset(changeset.indexed_tx_graph);
+ indexed_graph.apply_changeset(changeset.index_tx_graph);
let persist = Persist::new(db);
//!
//! [`SpkTxOutIndex`]: crate::SpkTxOutIndex
-use crate::{collections::BTreeMap, indexed_tx_graph, local_chain, Anchor, Append};
+use crate::{collections::BTreeMap, Append};
#[cfg(feature = "miniscript")]
mod txout_index;
}
}
-/// A structure that records the corresponding changes as result of applying an [`WalletUpdate`].
-#[derive(Debug, Clone, PartialEq)]
-#[cfg_attr(
- feature = "serde",
- derive(serde::Deserialize, serde::Serialize),
- serde(
- crate = "serde_crate",
- bound(
- deserialize = "K: Ord + serde::Deserialize<'de>, A: Ord + serde::Deserialize<'de>",
- serialize = "K: Ord + serde::Serialize, A: Ord + serde::Serialize",
- )
- )
-)]
-pub struct WalletChangeSet<K, A> {
- /// Changes to the [`LocalChain`].
- ///
- /// [`LocalChain`]: local_chain::LocalChain
- pub chain: local_chain::ChangeSet,
-
- /// ChangeSet to [`IndexedTxGraph`].
- ///
- /// [`IndexedTxGraph`]: crate::indexed_tx_graph::IndexedTxGraph
- pub indexed_tx_graph: indexed_tx_graph::ChangeSet<A, ChangeSet<K>>,
-}
-
-impl<K, A> Default for WalletChangeSet<K, A> {
- fn default() -> Self {
- Self {
- chain: Default::default(),
- indexed_tx_graph: Default::default(),
- }
- }
-}
-
-impl<K: Ord, A: Anchor> Append for WalletChangeSet<K, A> {
- fn append(&mut self, other: Self) {
- Append::append(&mut self.chain, other.chain);
- Append::append(&mut self.indexed_tx_graph, other.indexed_tx_graph);
- }
-
- fn is_empty(&self) -> bool {
- self.chain.is_empty() && self.indexed_tx_graph.is_empty()
- }
-}
-
-impl<K, A> From<local_chain::ChangeSet> for WalletChangeSet<K, A> {
- fn from(chain: local_chain::ChangeSet) -> Self {
- Self {
- chain,
- ..Default::default()
- }
- }
-}
-
-impl<K, A> From<indexed_tx_graph::ChangeSet<A, ChangeSet<K>>> for WalletChangeSet<K, A> {
- fn from(indexed_tx_graph: indexed_tx_graph::ChangeSet<A, ChangeSet<K>>) -> Self {
- Self {
- indexed_tx_graph,
- ..Default::default()
- }
- }
-}
-
/// Balance, differentiated into various categories.
#[derive(Debug, PartialEq, Eq, Clone, Default)]
#[cfg_attr(
/// How many confirmations are needed f or a coinbase output to be spent.
pub const COINBASE_MATURITY: u32 = 100;
+
+impl<A, IA> From<indexed_tx_graph::ChangeSet<A, IA>>
+ for (local_chain::ChangeSet, indexed_tx_graph::ChangeSet<A, IA>)
+{
+ fn from(indexed_changeset: indexed_tx_graph::ChangeSet<A, IA>) -> Self {
+ (local_chain::ChangeSet::default(), indexed_changeset)
+ }
+}
use bdk_chain::{
bitcoin::{Address, Network, OutPoint, ScriptBuf, Txid},
indexed_tx_graph::{self, IndexedTxGraph},
- keychain::WalletChangeSet,
+ keychain,
local_chain::{self, LocalChain},
Append, ConfirmationHeightAnchor,
};
pub batch_size: usize,
}
-type ChangeSet = WalletChangeSet<Keychain, ConfirmationHeightAnchor>;
+type ChangeSet = (
+ local_chain::ChangeSet,
+ indexed_tx_graph::ChangeSet<ConfirmationHeightAnchor, keychain::ChangeSet<Keychain>>,
+);
fn main() -> anyhow::Result<()> {
let (args, keymap, index, db, init_changeset) =
let graph = Mutex::new({
let mut graph = IndexedTxGraph::new(index);
- graph.apply_changeset(init_changeset.indexed_tx_graph);
+ graph.apply_changeset(init_changeset.1);
graph
});
- let chain = Mutex::new(LocalChain::from_changeset(init_changeset.chain));
+ let chain = Mutex::new(LocalChain::from_changeset(init_changeset.0));
let electrum_url = match args.network {
Network::Bitcoin => "ssl://electrum.blockstream.info:50002",
changeset
};
- ChangeSet {
- indexed_tx_graph,
- chain,
- }
+ (chain, indexed_tx_graph)
};
let mut db = db.lock().unwrap();
use bdk_chain::{
bitcoin::{Address, Network, OutPoint, ScriptBuf, Txid},
- indexed_tx_graph::IndexedTxGraph,
- keychain::WalletChangeSet,
- local_chain::{CheckPoint, LocalChain},
+ indexed_tx_graph::{self, IndexedTxGraph},
+ keychain,
+ local_chain::{self, CheckPoint, LocalChain},
Append, ConfirmationTimeAnchor,
};
const DB_MAGIC: &[u8] = b"bdk_example_esplora";
const DB_PATH: &str = ".bdk_esplora_example.db";
+type ChangeSet = (
+ local_chain::ChangeSet,
+ indexed_tx_graph::ChangeSet<ConfirmationTimeAnchor, keychain::ChangeSet<Keychain>>,
+);
+
#[derive(Subcommand, Debug, Clone)]
enum EsploraCommands {
/// Scans the addresses in the wallet using the esplora API.
}
fn main() -> anyhow::Result<()> {
- let (args, keymap, index, db, init_changeset) = example_cli::init::<
- EsploraCommands,
- WalletChangeSet<Keychain, ConfirmationTimeAnchor>,
- >(DB_MAGIC, DB_PATH)?;
+ let (args, keymap, index, db, init_changeset) =
+ example_cli::init::<EsploraCommands, ChangeSet>(DB_MAGIC, DB_PATH)?;
+
+ let (init_chain_changeset, init_indexed_tx_graph_changeset) = init_changeset;
// Contruct `IndexedTxGraph` and `LocalChain` with our initial changeset. They are wrapped in
// `Mutex` to display how they can be used in a multithreaded context. Technically the mutexes
// aren't strictly needed here.
let graph = Mutex::new({
let mut graph = IndexedTxGraph::new(index);
- graph.apply_changeset(init_changeset.indexed_tx_graph);
+ graph.apply_changeset(init_indexed_tx_graph_changeset);
graph
});
let chain = Mutex::new({
let mut chain = LocalChain::default();
- chain.apply_changeset(&init_changeset.chain);
+ chain.apply_changeset(&init_chain_changeset);
chain
});
println!("missing block heights: {:?}", missing_block_heights);
// Here, we actually fetch the missing blocks and create a `local_chain::Update`.
- let chain_update = client
- .update_local_chain(tip, missing_block_heights)
- .context("scanning for blocks")?;
-
- println!("new tip: {}", chain_update.tip.height());
+ let chain_changeset = {
+ let chain_update = client
+ .update_local_chain(tip, missing_block_heights)
+ .context("scanning for blocks")?;
+ println!("new tip: {}", chain_update.tip.height());
+ chain.lock().unwrap().apply_update(chain_update)?
+ };
// We persist the changes
let mut db = db.lock().unwrap();
- db.stage(WalletChangeSet {
- chain: chain.lock().unwrap().apply_update(chain_update)?,
- indexed_tx_graph: indexed_tx_graph_changeset,
- });
+ db.stage((chain_changeset, indexed_tx_graph_changeset));
db.commit()?;
Ok(())
}