From 68572bfd2e32efdeefaa46618e8e248d3a87f143 Mon Sep 17 00:00:00 2001 From: Vladimir Fomene Date: Mon, 21 Aug 2023 15:18:16 +0300 Subject: [PATCH] refactor: move WalletChangeset to wallet module Consequently, remove the `WalletChangeset` dependency from `example_electrum` and `example_esplora` examples. --- crates/bdk/src/wallet/mod.rs | 62 +++++++++++++++++++- crates/chain/src/keychain.rs | 65 +-------------------- crates/chain/src/lib.rs | 8 +++ example-crates/example_electrum/src/main.rs | 16 ++--- example-crates/example_esplora/src/main.rs | 40 +++++++------ 5 files changed, 98 insertions(+), 93 deletions(-) diff --git a/crates/bdk/src/wallet/mod.rs b/crates/bdk/src/wallet/mod.rs index 1fe16147..47dd03de 100644 --- a/crates/bdk/src/wallet/mod.rs +++ b/crates/bdk/src/wallet/mod.rs @@ -22,10 +22,10 @@ use alloc::{ 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; @@ -124,6 +124,62 @@ impl WalletUpdate { } } +/// A structure that records the corresponding changes as result of applying an [`WalletUpdate`]. +#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)] +pub struct WalletChangeSet { + /// 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>, +} + +impl Default for WalletChangeSet { + fn default() -> Self { + Self { + chain: Default::default(), + index_tx_graph: Default::default(), + } + } +} + +impl Append for WalletChangeSet { + 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 From for WalletChangeSet { + fn from(chain: local_chain::ChangeSet) -> Self { + Self { + chain, + ..Default::default() + } + } +} + +impl From>> for WalletChangeSet { + fn from(index_tx_graph: indexed_tx_graph::ChangeSet>) -> 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; @@ -277,7 +333,7 @@ impl Wallet { 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); diff --git a/crates/chain/src/keychain.rs b/crates/chain/src/keychain.rs index 74e98242..63972a0a 100644 --- a/crates/chain/src/keychain.rs +++ b/crates/chain/src/keychain.rs @@ -10,7 +10,7 @@ //! //! [`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; @@ -80,69 +80,6 @@ impl AsRef> for ChangeSet { } } -/// 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 { - /// 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>, -} - -impl Default for WalletChangeSet { - fn default() -> Self { - Self { - chain: Default::default(), - indexed_tx_graph: Default::default(), - } - } -} - -impl Append for WalletChangeSet { - 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 From for WalletChangeSet { - fn from(chain: local_chain::ChangeSet) -> Self { - Self { - chain, - ..Default::default() - } - } -} - -impl From>> for WalletChangeSet { - fn from(indexed_tx_graph: indexed_tx_graph::ChangeSet>) -> Self { - Self { - indexed_tx_graph, - ..Default::default() - } - } -} - /// Balance, differentiated into various categories. #[derive(Debug, PartialEq, Eq, Clone, Default)] #[cfg_attr( diff --git a/crates/chain/src/lib.rs b/crates/chain/src/lib.rs index ed167ebf..f38b7ee5 100644 --- a/crates/chain/src/lib.rs +++ b/crates/chain/src/lib.rs @@ -100,3 +100,11 @@ pub mod collections { /// How many confirmations are needed f or a coinbase output to be spent. pub const COINBASE_MATURITY: u32 = 100; + +impl From> + for (local_chain::ChangeSet, indexed_tx_graph::ChangeSet) +{ + fn from(indexed_changeset: indexed_tx_graph::ChangeSet) -> Self { + (local_chain::ChangeSet::default(), indexed_changeset) + } +} diff --git a/example-crates/example_electrum/src/main.rs b/example-crates/example_electrum/src/main.rs index 56cc144c..f8bb10b1 100644 --- a/example-crates/example_electrum/src/main.rs +++ b/example-crates/example_electrum/src/main.rs @@ -7,7 +7,7 @@ use std::{ use bdk_chain::{ bitcoin::{Address, Network, OutPoint, ScriptBuf, Txid}, indexed_tx_graph::{self, IndexedTxGraph}, - keychain::WalletChangeSet, + keychain, local_chain::{self, LocalChain}, Append, ConfirmationHeightAnchor, }; @@ -60,7 +60,10 @@ pub struct ScanOptions { pub batch_size: usize, } -type ChangeSet = WalletChangeSet; +type ChangeSet = ( + local_chain::ChangeSet, + indexed_tx_graph::ChangeSet>, +); fn main() -> anyhow::Result<()> { let (args, keymap, index, db, init_changeset) = @@ -68,11 +71,11 @@ fn main() -> anyhow::Result<()> { 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", @@ -293,10 +296,7 @@ fn main() -> anyhow::Result<()> { changeset }; - ChangeSet { - indexed_tx_graph, - chain, - } + (chain, indexed_tx_graph) }; let mut db = db.lock().unwrap(); diff --git a/example-crates/example_esplora/src/main.rs b/example-crates/example_esplora/src/main.rs index f33125be..9559e1d3 100644 --- a/example-crates/example_esplora/src/main.rs +++ b/example-crates/example_esplora/src/main.rs @@ -6,9 +6,9 @@ use std::{ 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, }; @@ -23,6 +23,11 @@ use example_cli::{ 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>, +); + #[derive(Subcommand, Debug, Clone)] enum EsploraCommands { /// Scans the addresses in the wallet using the esplora API. @@ -60,22 +65,22 @@ pub struct ScanOptions { } fn main() -> anyhow::Result<()> { - let (args, keymap, index, db, init_changeset) = example_cli::init::< - EsploraCommands, - WalletChangeSet, - >(DB_MAGIC, DB_PATH)?; + let (args, keymap, index, db, init_changeset) = + example_cli::init::(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 }); @@ -307,18 +312,17 @@ fn main() -> anyhow::Result<()> { 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(()) }