]> Untitled Git - bdk/commitdiff
feat!: rm `persist` submodule
author志宇 <hello@evanlinjin.me>
Fri, 14 Jun 2024 12:42:25 +0000 (20:42 +0800)
committer志宇 <hello@evanlinjin.me>
Fri, 14 Jun 2024 16:52:23 +0000 (00:52 +0800)
Remove `PersistBackend`, `PersistBackendAsync`, `StageExt` and
`StageExtAsync`. Remove `async` feature flag and dependency. Update
examples and wallet.

18 files changed:
crates/chain/Cargo.toml
crates/chain/src/changeset.rs [new file with mode: 0644]
crates/chain/src/lib.rs
crates/chain/src/persist.rs [deleted file]
crates/file_store/README.md
crates/file_store/src/store.rs
crates/sqlite/src/store.rs
crates/wallet/Cargo.toml
crates/wallet/src/wallet/mod.rs
crates/wallet/tests/wallet.rs
example-crates/example_bitcoind_rpc_polling/src/main.rs
example-crates/example_cli/src/lib.rs
example-crates/example_electrum/src/main.rs
example-crates/example_esplora/src/main.rs
example-crates/wallet_electrum/src/main.rs
example-crates/wallet_esplora_async/src/main.rs
example-crates/wallet_esplora_blocking/src/main.rs
example-crates/wallet_rpc/src/main.rs

index 293a24458c2804657d6468ac88cde1d0a8d640ea..8b4a3c3286b72739f0b868332abf1337651f4659 100644 (file)
@@ -19,7 +19,6 @@ serde_crate = { package = "serde", version = "1", optional = true, features = ["
 # Use hashbrown as a feature flag to have HashSet and HashMap from it.
 hashbrown = { version = "0.9.1", optional = true, features = ["serde"] }
 miniscript = { version = "12.0.0", optional = true, default-features = false }
-async-trait = {  version = "0.1.80", optional = true }
 
 [dev-dependencies]
 rand = "0.8"
@@ -29,4 +28,3 @@ proptest = "1.2.0"
 default = ["std", "miniscript"]
 std = ["bitcoin/std", "miniscript?/std"]
 serde = ["serde_crate", "bitcoin/serde", "miniscript?/serde"]
-async = ["async-trait"]
diff --git a/crates/chain/src/changeset.rs b/crates/chain/src/changeset.rs
new file mode 100644 (file)
index 0000000..2612884
--- /dev/null
@@ -0,0 +1,95 @@
+//! This module is home to the [`PersistBackend`] trait which defines the behavior of a data store
+//! required to persist changes made to BDK data structures.
+//!
+//! The [`CombinedChangeSet`] type encapsulates a combination of [`crate`] structures that are
+//! typically persisted together.
+
+/// A changeset containing [`crate`] structures typically persisted together.
+#[cfg(feature = "miniscript")]
+#[derive(Debug, Clone, PartialEq)]
+#[cfg_attr(
+    feature = "serde",
+    derive(crate::serde::Deserialize, crate::serde::Serialize),
+    serde(
+        crate = "crate::serde",
+        bound(
+            deserialize = "A: Ord + crate::serde::Deserialize<'de>, K: Ord + crate::serde::Deserialize<'de>",
+            serialize = "A: Ord + crate::serde::Serialize, K: Ord + crate::serde::Serialize",
+        ),
+    )
+)]
+pub struct CombinedChangeSet<K, A> {
+    /// Changes to the [`LocalChain`](crate::local_chain::LocalChain).
+    pub chain: crate::local_chain::ChangeSet,
+    /// Changes to [`IndexedTxGraph`](crate::indexed_tx_graph::IndexedTxGraph).
+    pub indexed_tx_graph: crate::indexed_tx_graph::ChangeSet<A, crate::keychain::ChangeSet<K>>,
+    /// Stores the network type of the transaction data.
+    pub network: Option<bitcoin::Network>,
+}
+
+#[cfg(feature = "miniscript")]
+impl<K, A> core::default::Default for CombinedChangeSet<K, A> {
+    fn default() -> Self {
+        Self {
+            chain: core::default::Default::default(),
+            indexed_tx_graph: core::default::Default::default(),
+            network: None,
+        }
+    }
+}
+
+#[cfg(feature = "miniscript")]
+impl<K: Ord, A: crate::Anchor> crate::Append for CombinedChangeSet<K, A> {
+    fn append(&mut self, other: Self) {
+        crate::Append::append(&mut self.chain, other.chain);
+        crate::Append::append(&mut self.indexed_tx_graph, other.indexed_tx_graph);
+        if other.network.is_some() {
+            debug_assert!(
+                self.network.is_none() || self.network == other.network,
+                "network type must either be just introduced or remain the same"
+            );
+            self.network = other.network;
+        }
+    }
+
+    fn is_empty(&self) -> bool {
+        self.chain.is_empty() && self.indexed_tx_graph.is_empty() && self.network.is_none()
+    }
+}
+
+#[cfg(feature = "miniscript")]
+impl<K, A> From<crate::local_chain::ChangeSet> for CombinedChangeSet<K, A> {
+    fn from(chain: crate::local_chain::ChangeSet) -> Self {
+        Self {
+            chain,
+            ..Default::default()
+        }
+    }
+}
+
+#[cfg(feature = "miniscript")]
+impl<K, A> From<crate::indexed_tx_graph::ChangeSet<A, crate::keychain::ChangeSet<K>>>
+    for CombinedChangeSet<K, A>
+{
+    fn from(
+        indexed_tx_graph: crate::indexed_tx_graph::ChangeSet<A, crate::keychain::ChangeSet<K>>,
+    ) -> Self {
+        Self {
+            indexed_tx_graph,
+            ..Default::default()
+        }
+    }
+}
+
+#[cfg(feature = "miniscript")]
+impl<K, A> From<crate::keychain::ChangeSet<K>> for CombinedChangeSet<K, A> {
+    fn from(indexer: crate::keychain::ChangeSet<K>) -> Self {
+        Self {
+            indexed_tx_graph: crate::indexed_tx_graph::ChangeSet {
+                indexer,
+                ..Default::default()
+            },
+            ..Default::default()
+        }
+    }
+}
index 7a5036a2f0926569ead6d882ea3f5c6e6b1b9c94..94f81441eabd0735d5e6de56f69015f9b06cf3f9 100644 (file)
@@ -50,7 +50,8 @@ pub use descriptor_ext::{DescriptorExt, DescriptorId};
 mod spk_iter;
 #[cfg(feature = "miniscript")]
 pub use spk_iter::*;
-pub mod persist;
+mod changeset;
+pub use changeset::*;
 pub mod spk_client;
 
 #[allow(unused_imports)]
diff --git a/crates/chain/src/persist.rs b/crates/chain/src/persist.rs
deleted file mode 100644 (file)
index 9fe69cf..0000000
+++ /dev/null
@@ -1,279 +0,0 @@
-//! This module is home to the [`PersistBackend`] trait which defines the behavior of a data store
-//! required to persist changes made to BDK data structures.
-//!
-//! The [`CombinedChangeSet`] type encapsulates a combination of [`crate`] structures that are
-//! typically persisted together.
-
-#[cfg(feature = "async")]
-use alloc::boxed::Box;
-#[cfg(feature = "async")]
-use async_trait::async_trait;
-use core::convert::Infallible;
-use core::fmt::{Debug, Display};
-
-use crate::Append;
-
-/// A changeset containing [`crate`] structures typically persisted together.
-#[derive(Debug, Clone, PartialEq)]
-#[cfg(feature = "miniscript")]
-#[cfg_attr(
-    feature = "serde",
-    derive(crate::serde::Deserialize, crate::serde::Serialize),
-    serde(
-        crate = "crate::serde",
-        bound(
-            deserialize = "A: Ord + crate::serde::Deserialize<'de>, K: Ord + crate::serde::Deserialize<'de>",
-            serialize = "A: Ord + crate::serde::Serialize, K: Ord + crate::serde::Serialize",
-        ),
-    )
-)]
-pub struct CombinedChangeSet<K, A> {
-    /// Changes to the [`LocalChain`](crate::local_chain::LocalChain).
-    pub chain: crate::local_chain::ChangeSet,
-    /// Changes to [`IndexedTxGraph`](crate::indexed_tx_graph::IndexedTxGraph).
-    pub indexed_tx_graph: crate::indexed_tx_graph::ChangeSet<A, crate::keychain::ChangeSet<K>>,
-    /// Stores the network type of the transaction data.
-    pub network: Option<bitcoin::Network>,
-}
-
-#[cfg(feature = "miniscript")]
-impl<K, A> core::default::Default for CombinedChangeSet<K, A> {
-    fn default() -> Self {
-        Self {
-            chain: core::default::Default::default(),
-            indexed_tx_graph: core::default::Default::default(),
-            network: None,
-        }
-    }
-}
-
-#[cfg(feature = "miniscript")]
-impl<K: Ord, A: crate::Anchor> crate::Append for CombinedChangeSet<K, A> {
-    fn append(&mut self, other: Self) {
-        crate::Append::append(&mut self.chain, other.chain);
-        crate::Append::append(&mut self.indexed_tx_graph, other.indexed_tx_graph);
-        if other.network.is_some() {
-            debug_assert!(
-                self.network.is_none() || self.network == other.network,
-                "network type must either be just introduced or remain the same"
-            );
-            self.network = other.network;
-        }
-    }
-
-    fn is_empty(&self) -> bool {
-        self.chain.is_empty() && self.indexed_tx_graph.is_empty() && self.network.is_none()
-    }
-}
-
-#[cfg(feature = "miniscript")]
-impl<K, A> From<crate::local_chain::ChangeSet> for CombinedChangeSet<K, A> {
-    fn from(chain: crate::local_chain::ChangeSet) -> Self {
-        Self {
-            chain,
-            ..Default::default()
-        }
-    }
-}
-
-#[cfg(feature = "miniscript")]
-impl<K, A> From<crate::indexed_tx_graph::ChangeSet<A, crate::keychain::ChangeSet<K>>>
-    for CombinedChangeSet<K, A>
-{
-    fn from(
-        indexed_tx_graph: crate::indexed_tx_graph::ChangeSet<A, crate::keychain::ChangeSet<K>>,
-    ) -> Self {
-        Self {
-            indexed_tx_graph,
-            ..Default::default()
-        }
-    }
-}
-
-#[cfg(feature = "miniscript")]
-impl<K, A> From<crate::keychain::ChangeSet<K>> for CombinedChangeSet<K, A> {
-    fn from(indexer: crate::keychain::ChangeSet<K>) -> Self {
-        Self {
-            indexed_tx_graph: crate::indexed_tx_graph::ChangeSet {
-                indexer,
-                ..Default::default()
-            },
-            ..Default::default()
-        }
-    }
-}
-
-/// A persistence backend for writing and loading changesets.
-///
-/// `C` represents the changeset; a datatype that records changes made to in-memory data structures
-/// that are to be persisted, or retrieved from persistence.
-pub trait PersistBackend<C> {
-    /// The error the backend returns when it fails to write.
-    type WriteError: Debug + Display;
-
-    /// The error the backend returns when it fails to load changesets `C`.
-    type LoadError: Debug + Display;
-
-    /// Writes a changeset to the persistence backend.
-    ///
-    /// It is up to the backend what it does with this. It could store every changeset in a list or
-    /// it inserts the actual changes into a more structured database. All it needs to guarantee is
-    /// that [`load_from_persistence`] restores a keychain tracker to what it should be if all
-    /// changesets had been applied sequentially.
-    ///
-    /// [`load_from_persistence`]: Self::load_changes
-    fn write_changes(&mut self, changeset: &C) -> Result<(), Self::WriteError>;
-
-    /// Return the aggregate changeset `C` from persistence.
-    fn load_changes(&mut self) -> Result<Option<C>, Self::LoadError>;
-}
-
-impl<C> PersistBackend<C> for () {
-    type WriteError = Infallible;
-    type LoadError = Infallible;
-
-    fn write_changes(&mut self, _changeset: &C) -> Result<(), Self::WriteError> {
-        Ok(())
-    }
-
-    fn load_changes(&mut self) -> Result<Option<C>, Self::LoadError> {
-        Ok(None)
-    }
-}
-
-#[cfg(feature = "async")]
-/// An async persistence backend for writing and loading changesets.
-///
-/// `C` represents the changeset; a datatype that records changes made to in-memory data structures
-/// that are to be persisted, or retrieved from persistence.
-#[async_trait]
-pub trait PersistBackendAsync<C> {
-    /// The error the backend returns when it fails to write.
-    type WriteError: Debug + Display;
-
-    /// The error the backend returns when it fails to load changesets `C`.
-    type LoadError: Debug + Display;
-
-    /// Writes a changeset to the persistence backend.
-    ///
-    /// It is up to the backend what it does with this. It could store every changeset in a list or
-    /// it inserts the actual changes into a more structured database. All it needs to guarantee is
-    /// that [`load_from_persistence`] restores a keychain tracker to what it should be if all
-    /// changesets had been applied sequentially.
-    ///
-    /// [`load_from_persistence`]: Self::load_changes
-    async fn write_changes(&mut self, changeset: &C) -> Result<(), Self::WriteError>;
-
-    /// Return the aggregate changeset `C` from persistence.
-    async fn load_changes(&mut self) -> Result<Option<C>, Self::LoadError>;
-}
-
-#[cfg(feature = "async")]
-#[async_trait]
-impl<C> PersistBackendAsync<C> for () {
-    type WriteError = Infallible;
-    type LoadError = Infallible;
-
-    async fn write_changes(&mut self, _changeset: &C) -> Result<(), Self::WriteError> {
-        Ok(())
-    }
-
-    async fn load_changes(&mut self) -> Result<Option<C>, Self::LoadError> {
-        Ok(None)
-    }
-}
-
-/// Extends a changeset so that it acts as a convenient staging area for any [`PersistBackend`].
-///
-/// Not all changes to the in-memory representation needs to be written to disk right away.
-/// [`Append::append`] can be used to *stage* changes first and then [`StageExt::commit_to`] can be
-/// used to write changes to disk.
-pub trait StageExt: Append + Default + Sized {
-    /// Commit the staged changes to the persistence `backend`.
-    ///
-    /// Changes that are committed (if any) are returned.
-    ///
-    /// # Error
-    ///
-    /// Returns a backend-defined error if this fails.
-    fn commit_to<B>(&mut self, backend: &mut B) -> Result<Option<Self>, B::WriteError>
-    where
-        B: PersistBackend<Self>,
-    {
-        // do not do anything if changeset is empty
-        if self.is_empty() {
-            return Ok(None);
-        }
-        backend.write_changes(&*self)?;
-        // only clear if changes are written successfully to backend
-        Ok(Some(core::mem::take(self)))
-    }
-
-    /// Stages a new `changeset` and commits it (alongside any other previously staged changes) to
-    /// the persistence `backend`.
-    ///
-    /// Convenience method for calling [`Append::append`] and then [`StageExt::commit_to`].
-    fn append_and_commit_to<B>(
-        &mut self,
-        changeset: Self,
-        backend: &mut B,
-    ) -> Result<Option<Self>, B::WriteError>
-    where
-        B: PersistBackend<Self>,
-    {
-        Append::append(self, changeset);
-        self.commit_to(backend)
-    }
-}
-
-impl<C: Append + Default> StageExt for C {}
-
-/// Extends a changeset so that it acts as a convenient staging area for any
-/// [`PersistBackendAsync`].
-///
-/// Not all changes to the in-memory representation needs to be written to disk right away.
-/// [`Append::append`] can be used to *stage* changes first and then [`StageExtAsync::commit_to`]
-/// can be used to write changes to disk.
-#[cfg(feature = "async")]
-#[async_trait]
-pub trait StageExtAsync: Append + Default + Sized + Send + Sync {
-    /// Commit the staged changes to the persistence `backend`.
-    ///
-    /// Changes that are committed (if any) are returned.
-    ///
-    /// # Error
-    ///
-    /// Returns a backend-defined error if this fails.
-    async fn commit_to<B>(&mut self, backend: &mut B) -> Result<Option<Self>, B::WriteError>
-    where
-        B: PersistBackendAsync<Self> + Send + Sync,
-    {
-        // do not do anything if changeset is empty
-        if self.is_empty() {
-            return Ok(None);
-        }
-        backend.write_changes(&*self).await?;
-        // only clear if changes are written successfully to backend
-        Ok(Some(core::mem::take(self)))
-    }
-
-    /// Stages a new `changeset` and commits it (alongside any other previously staged changes) to
-    /// the persistence `backend`.
-    ///
-    /// Convenience method for calling [`Append::append`] and then [`StageExtAsync::commit_to`].
-    async fn append_and_commit_to<B>(
-        &mut self,
-        changeset: Self,
-        backend: &mut B,
-    ) -> Result<Option<Self>, B::WriteError>
-    where
-        B: PersistBackendAsync<Self> + Send + Sync,
-    {
-        Append::append(self, changeset);
-        self.commit_to(backend).await
-    }
-}
-
-#[cfg(feature = "async")]
-#[async_trait]
-impl<C: Append + Default + Send + Sync> StageExtAsync for C {}
index cad196b2ddc3c14f54e99cc1b244ed0f3ec940ac..7b00aa0e02a07fc2487168f46e09f088825a8ab5 100644 (file)
@@ -1,6 +1,6 @@
 # BDK File Store
 
-This is a simple append-only flat file implementation of [`PersistBackend`](bdk_chain::persist::PersistBackend).
+This is a simple append-only flat file database for persisting [`bdk_chain`] changesets.
 
 The main structure is [`Store`] which works with any [`bdk_chain`] based changesets to persist data into a flat file.
 
index 2f451db722016ae5299bdad158ed0b0f3a18cb07..26a08809d265cd98a8ab95ca0a8b95451f75a8af 100644 (file)
@@ -1,5 +1,4 @@
 use crate::{bincode_options, EntryIter, FileError, IterError};
-use bdk_chain::persist::PersistBackend;
 use bdk_chain::Append;
 use bincode::Options;
 use std::{
@@ -21,27 +20,6 @@ where
     marker: PhantomData<C>,
 }
 
-impl<C> PersistBackend<C> for Store<C>
-where
-    C: Append
-        + Debug
-        + serde::Serialize
-        + serde::de::DeserializeOwned
-        + core::marker::Send
-        + core::marker::Sync,
-{
-    type WriteError = io::Error;
-    type LoadError = AggregateChangesetsError<C>;
-
-    fn write_changes(&mut self, changeset: &C) -> Result<(), Self::WriteError> {
-        self.append_changeset(changeset)
-    }
-
-    fn load_changes(&mut self) -> Result<Option<C>, Self::LoadError> {
-        self.aggregate_changesets()
-    }
-}
-
 impl<C> Store<C>
 where
     C: Append
@@ -448,7 +426,7 @@ mod test {
                     acc
                 });
             // We write after a short read.
-            db.write_changes(&last_changeset)
+            db.append_changeset(&last_changeset)
                 .expect("last write must succeed");
             Append::append(&mut exp_aggregation, last_changeset.clone());
             drop(db);
index 5bead7bc998472072b84c61aacdb1c4153c531f4..4cd81f50b28d5a05b2904e3b70ef164790a31e49 100644 (file)
@@ -12,7 +12,7 @@ use std::str::FromStr;
 use std::sync::{Arc, Mutex};
 
 use crate::Error;
-use bdk_chain::persist::{CombinedChangeSet, PersistBackend};
+use bdk_chain::CombinedChangeSet;
 use bdk_chain::{
     indexed_tx_graph, keychain, local_chain, tx_graph, Anchor, Append, DescriptorExt, DescriptorId,
 };
@@ -57,26 +57,6 @@ where
     }
 }
 
-impl<K, A> PersistBackend<CombinedChangeSet<K, A>> for Store<K, A>
-where
-    K: Ord + for<'de> Deserialize<'de> + Serialize + Send,
-    A: Anchor + for<'de> Deserialize<'de> + Serialize + Send,
-{
-    type WriteError = Error;
-    type LoadError = Error;
-
-    fn write_changes(
-        &mut self,
-        changeset: &CombinedChangeSet<K, A>,
-    ) -> Result<(), Self::WriteError> {
-        self.write(changeset)
-    }
-
-    fn load_changes(&mut self) -> Result<Option<CombinedChangeSet<K, A>>, Self::LoadError> {
-        self.read()
-    }
-}
-
 /// Network table related functions.
 impl<K, A> Store<K, A> {
     /// Insert [`Network`] for which all other tables data is valid.
@@ -482,13 +462,14 @@ where
     }
 }
 
-/// Functions to read and write all [`ChangeSet`] data.
+/// Functions to read and write all [`CombinedChangeSet`] data.
 impl<K, A> Store<K, A>
 where
     K: Ord + for<'de> Deserialize<'de> + Serialize + Send,
     A: Anchor + for<'de> Deserialize<'de> + Serialize + Send,
 {
-    fn write(&mut self, changeset: &CombinedChangeSet<K, A>) -> Result<(), Error> {
+    /// Write the given `changeset` atomically.
+    pub fn write(&mut self, changeset: &CombinedChangeSet<K, A>) -> Result<(), Error> {
         // no need to write anything if changeset is empty
         if changeset.is_empty() {
             return Ok(());
@@ -513,7 +494,8 @@ where
         db_transaction.commit().map_err(Error::Sqlite)
     }
 
-    fn read(&mut self) -> Result<Option<CombinedChangeSet<K, A>>, Error> {
+    /// Read the entire database and return the aggregate [`CombinedChangeSet`].
+    pub fn read(&mut self) -> Result<Option<CombinedChangeSet<K, A>>, Error> {
         let db_transaction = self.db_transaction()?;
 
         let network = Self::select_network(&db_transaction)?;
@@ -563,7 +545,7 @@ mod test {
     use bdk_chain::bitcoin::Network::Testnet;
     use bdk_chain::bitcoin::{secp256k1, BlockHash, OutPoint};
     use bdk_chain::miniscript::Descriptor;
-    use bdk_chain::persist::{CombinedChangeSet, PersistBackend};
+    use bdk_chain::CombinedChangeSet;
     use bdk_chain::{
         indexed_tx_graph, keychain, tx_graph, BlockId, ConfirmationHeightAnchor,
         ConfirmationTimeHeightAnchor, DescriptorExt,
@@ -591,10 +573,10 @@ mod test {
             .expect("create new memory db store");
 
         test_changesets.iter().for_each(|changeset| {
-            store.write_changes(changeset).expect("write changeset");
+            store.write(changeset).expect("write changeset");
         });
 
-        let agg_changeset = store.load_changes().expect("aggregated changeset");
+        let agg_changeset = store.read().expect("aggregated changeset");
 
         assert_eq!(agg_changeset, Some(agg_test_changesets));
     }
@@ -612,10 +594,10 @@ mod test {
             .expect("create new memory db store");
 
         test_changesets.iter().for_each(|changeset| {
-            store.write_changes(changeset).expect("write changeset");
+            store.write(changeset).expect("write changeset");
         });
 
-        let agg_changeset = store.load_changes().expect("aggregated changeset");
+        let agg_changeset = store.read().expect("aggregated changeset");
 
         assert_eq!(agg_changeset, Some(agg_test_changesets));
     }
@@ -629,10 +611,10 @@ mod test {
         let mut store = Store::<Keychain, BlockId>::new(conn).expect("create new memory db store");
 
         test_changesets.iter().for_each(|changeset| {
-            store.write_changes(changeset).expect("write changeset");
+            store.write(changeset).expect("write changeset");
         });
 
-        let agg_changeset = store.load_changes().expect("aggregated changeset");
+        let agg_changeset = store.read().expect("aggregated changeset");
 
         assert_eq!(agg_changeset, Some(agg_test_changesets));
     }
index d5b52be06018330f4e7fadd6e84e9d6559c158c4..d7f3290ace59b566263bbe0df12b3af434b1a942 100644 (file)
@@ -30,7 +30,6 @@ js-sys = "0.3"
 [features]
 default = ["std"]
 std = ["bitcoin/std", "miniscript/std", "bdk_chain/std"]
-async = ["bdk_chain/async"]
 compiler = ["miniscript/compiler"]
 all-keys = ["keys-bip39"]
 keys-bip39 = ["bip39"]
index 5a21c151869d1ad0806a4e83063cb3989cad88c0..c3e8fd7c3d438cf9d2ad207f4596646d968919f7 100644 (file)
@@ -26,7 +26,6 @@ use bdk_chain::{
     local_chain::{
         self, ApplyHeaderError, CannotConnectError, CheckPoint, CheckPointIter, LocalChain,
     },
-    persist::{PersistBackend, StageExt},
     spk_client::{FullScanRequest, FullScanResult, SyncRequest, SyncResult},
     tx_graph::{CanonicalTx, TxGraph},
     Append, BlockId, ChainPosition, ConfirmationTime, ConfirmationTimeHeightAnchor, FullTxOut,
@@ -85,12 +84,12 @@ const COINBASE_MATURITY: u32 = 100;
 /// 1. output *descriptors* from which it can derive addresses.
 /// 2. [`signer`]s that can contribute signatures to addresses instantiated from the descriptors.
 ///
-/// The user is responsible for loading and writing wallet changes using an implementation of
-/// [`PersistBackend`]. See individual functions and example for instructions on when [`Wallet`]
-/// state needs to be persisted.
+/// The user is responsible for loading and writing wallet changes which are represented as
+/// [`ChangeSet`]s (see [`take_staged`]). Also see individual functions and example for instructions
+/// on when [`Wallet`] state needs to be persisted.
 ///
-/// [`PersistBackend`]: bdk_chain::persist::PersistBackend
 /// [`signer`]: crate::signer
+/// [`take_staged`]: Wallet::take_staged
 #[derive(Debug)]
 pub struct Wallet {
     signers: Arc<SignersContainer>,
@@ -141,8 +140,7 @@ impl From<SyncResult> for Update {
 }
 
 /// The changes made to a wallet by applying an [`Update`].
-pub type ChangeSet =
-    bdk_chain::persist::CombinedChangeSet<KeychainKind, ConfirmationTimeHeightAnchor>;
+pub type ChangeSet = bdk_chain::CombinedChangeSet<KeychainKind, ConfirmationTimeHeightAnchor>;
 
 /// A derived address and the index it was found at.
 /// For convenience this automatically derefs to `Address`
@@ -408,14 +406,13 @@ impl Wallet {
     /// # use bdk_wallet::descriptor::Descriptor;
     /// # use bitcoin::key::Secp256k1;
     /// # use bdk_wallet::KeychainKind;
-    /// use bdk_sqlite::{Store, rusqlite::Connection};
+    /// use bdk_sqlite::{Store, rusqlite::Connection};
     /// #
     /// # fn main() -> Result<(), anyhow::Error> {
-    /// # use bdk_chain::persist::PersistBackend;
     /// # let temp_dir = tempfile::tempdir().expect("must create tempdir");
     /// # let file_path = temp_dir.path().join("store.db");
-    /// let conn = Connection::open(file_path).expect("must open connection");
-    /// let mut db = Store::new(conn).expect("must create db");
+    /// let conn = Connection::open(file_path).expect("must open connection");
+    /// let mut db = Store::new(conn).expect("must create db");
     /// let secp = Secp256k1::new();
     ///
     /// let (external_descriptor, external_keymap) = Descriptor::parse_descriptor(&secp, "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/1'/0'/0/*)").unwrap();
@@ -423,7 +420,7 @@ impl Wallet {
     ///
     /// let external_signer_container = SignersContainer::build(external_keymap, &external_descriptor, &secp);
     /// let internal_signer_container = SignersContainer::build(internal_keymap, &internal_descriptor, &secp);
-    /// let changeset = db.load_changes()?.expect("there must be an existing changeset");
+    /// let changeset = db.read()?.expect("there must be an existing changeset");
     /// let mut wallet = Wallet::load_from_changeset(changeset)?;
     ///
     /// external_signer_container.signers().into_iter()
@@ -482,13 +479,12 @@ impl Wallet {
     /// This method will fail if the loaded [`ChangeSet`] has different parameters to those provided.
     ///
     /// ```rust,no_run
-    /// # use bdk_chain::persist::PersistBackend;
     /// # use bdk_wallet::Wallet;
-    /// use bdk_sqlite::{Store, rusqlite::Connection};
+    /// use bdk_sqlite::{Store, rusqlite::Connection};
     /// # use bitcoin::Network::Testnet;
-    /// let conn = Connection::open_in_memory().expect("must open connection");
+    /// let conn = Connection::open_in_memory().expect("must open connection");
     /// let mut db = Store::new(conn).expect("must create db");
-    /// let changeset = db.load_changes()?;
+    /// let changeset = db.read()?;
     ///
     /// let external_descriptor = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/1'/0'/0/*)";
     /// let internal_descriptor = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/1'/0'/1/*)";
@@ -666,16 +662,17 @@ impl Wallet {
     /// calls to this method before closing the wallet. For example:
     ///
     /// ```rust,no_run
-    /// # use bdk_chain::persist::PersistBackend;
     /// # use bdk_wallet::wallet::{Wallet, ChangeSet};
     /// # use bdk_wallet::KeychainKind;
-    /// # use bdk_sqlite::{Store, rusqlite::Connection};
-    /// let conn = Connection::open_in_memory().expect("must open connection");
-    /// let mut db = Store::new(conn).expect("must create store");
+    /// use bdk_sqlite::{rusqlite::Connection, Store};
+    /// let conn = Connection::open_in_memory().expect("must open connection");
+    /// let mut db = Store::new(conn).expect("must create store");
     /// # let changeset = ChangeSet::default();
     /// # let mut wallet = Wallet::load_from_changeset(changeset).expect("load wallet");
     /// let next_address = wallet.reveal_next_address(KeychainKind::External);
-    /// wallet.commit_to(&mut db)?;
+    /// if let Some(changeset) = wallet.take_staged() {
+    ///     db.write(&changeset)?;
+    /// }
     ///
     /// // Now it's safe to show the user their next address!
     /// println!("Next address: {}", next_address.address);
@@ -2283,44 +2280,22 @@ impl Wallet {
         Ok(())
     }
 
-    /// Commits all currently [`staged`](Wallet::staged) changes to the `persist_backend`.
-    ///
-    /// This returns whether anything was persisted.
-    ///
-    /// # Error
-    ///
-    /// Returns a backend-defined error if this fails.
-    pub fn commit_to<B>(&mut self, persist_backend: &mut B) -> Result<bool, B::WriteError>
-    where
-        B: PersistBackend<ChangeSet>,
-    {
-        let committed = StageExt::commit_to(&mut self.stage, persist_backend)?;
-        Ok(committed.is_some())
-    }
-
-    /// Commits all currently [`staged`](Wallet::staged) changes to the async `persist_backend`.
-    ///
-    /// This returns whether anything was persisted.
-    ///
-    /// # Error
-    ///
-    /// Returns a backend-defined error if this fails.
-    #[cfg(feature = "async")]
-    pub async fn commit_to_async<B>(
-        &mut self,
-        persist_backend: &mut B,
-    ) -> Result<bool, B::WriteError>
-    where
-        B: bdk_chain::persist::PersistBackendAsync<ChangeSet> + Send + Sync,
-    {
-        let committed =
-            bdk_chain::persist::StageExtAsync::commit_to(&mut self.stage, persist_backend).await?;
-        Ok(committed.is_some())
+    /// Get a reference of the staged [`ChangeSet`] that are yet to be committed (if any).
+    pub fn staged(&self) -> Option<&ChangeSet> {
+        if self.stage.is_empty() {
+            None
+        } else {
+            Some(&self.stage)
+        }
     }
 
-    /// Get the staged [`ChangeSet`] that is yet to be committed.
-    pub fn staged(&self) -> &ChangeSet {
-        &self.stage
+    /// Take the staged [`ChangeSet`] to be persisted now (if any).
+    pub fn take_staged(&mut self) -> Option<ChangeSet> {
+        if self.stage.is_empty() {
+            None
+        } else {
+            Some(core::mem::take(&mut self.stage))
+        }
     }
 
     /// Get a reference to the inner [`TxGraph`].
index 3ca18b76013949f34547e22125a60b88ec1042c3..7303bdcd8a57de3e0bc644588ce7970599ca0e45 100644 (file)
@@ -1,11 +1,10 @@
-use anyhow::anyhow;
 use std::path::Path;
 use std::str::FromStr;
 
 use assert_matches::assert_matches;
 use bdk_chain::collections::BTreeMap;
 use bdk_chain::COINBASE_MATURITY;
-use bdk_chain::{persist::PersistBackend, BlockId, ConfirmationTime};
+use bdk_chain::{BlockId, ConfirmationTime};
 use bdk_sqlite::rusqlite::Connection;
 use bdk_wallet::descriptor::{calc_checksum, DescriptorError, IntoWalletDescriptor};
 use bdk_wallet::psbt::PsbtUtils;
@@ -13,7 +12,7 @@ use bdk_wallet::signer::{SignOptions, SignerError};
 use bdk_wallet::wallet::coin_selection::{self, LargestFirstCoinSelection};
 use bdk_wallet::wallet::error::CreateTxError;
 use bdk_wallet::wallet::tx_builder::AddForeignUtxoError;
-use bdk_wallet::wallet::{AddressInfo, Balance, NewError, Wallet};
+use bdk_wallet::wallet::{AddressInfo, Balance, ChangeSet, NewError, Wallet};
 use bdk_wallet::KeychainKind;
 use bitcoin::hashes::Hash;
 use bitcoin::key::Secp256k1;
@@ -72,11 +71,18 @@ const DB_MAGIC: &[u8] = &[0x21, 0x24, 0x48];
 
 #[test]
 fn load_recovers_wallet() -> anyhow::Result<()> {
-    fn run<B, FN, FR>(filename: &str, create_new: FN, recover: FR) -> anyhow::Result<()>
+    fn run<Db, New, Recover, Read, Write>(
+        filename: &str,
+        create_new: New,
+        recover: Recover,
+        read: Read,
+        write: Write,
+    ) -> anyhow::Result<()>
     where
-        B: PersistBackend<bdk_wallet::wallet::ChangeSet> + Send + Sync + 'static,
-        FN: Fn(&Path) -> anyhow::Result<B>,
-        FR: Fn(&Path) -> anyhow::Result<B>,
+        New: Fn(&Path) -> anyhow::Result<Db>,
+        Recover: Fn(&Path) -> anyhow::Result<Db>,
+        Read: Fn(&mut Db) -> anyhow::Result<Option<ChangeSet>>,
+        Write: Fn(&mut Db, &ChangeSet) -> anyhow::Result<()>,
     {
         let temp_dir = tempfile::tempdir().expect("must create tempdir");
         let file_path = temp_dir.path().join(filename);
@@ -91,9 +97,9 @@ fn load_recovers_wallet() -> anyhow::Result<()> {
 
             // persist new wallet changes
             let mut db = create_new(&file_path).expect("must create db");
-            wallet
-                .commit_to(&mut db)
-                .map_err(|e| anyhow!("write changes error: {}", e))?;
+            if let Some(changeset) = wallet.take_staged() {
+                write(&mut db, &changeset)?;
+            }
             wallet.spk_index().clone()
         };
 
@@ -101,10 +107,7 @@ fn load_recovers_wallet() -> anyhow::Result<()> {
         {
             // load persisted wallet changes
             let db = &mut recover(&file_path).expect("must recover db");
-            let changeset = db
-                .load_changes()
-                .expect("must recover wallet")
-                .expect("changeset");
+            let changeset = read(db).expect("must recover wallet").expect("changeset");
 
             let wallet = Wallet::load_from_changeset(changeset).expect("must recover wallet");
             assert_eq!(wallet.network(), Network::Testnet);
@@ -132,11 +135,15 @@ fn load_recovers_wallet() -> anyhow::Result<()> {
         "store.db",
         |path| Ok(bdk_file_store::Store::create_new(DB_MAGIC, path)?),
         |path| Ok(bdk_file_store::Store::open(DB_MAGIC, path)?),
+        |db| Ok(bdk_file_store::Store::aggregate_changesets(db)?),
+        |db, changeset| Ok(bdk_file_store::Store::append_changeset(db, changeset)?),
     )?;
     run(
         "store.sqlite",
         |path| Ok(bdk_sqlite::Store::new(Connection::open(path)?)?),
         |path| Ok(bdk_sqlite::Store::new(Connection::open(path)?)?),
+        |db| Ok(bdk_sqlite::Store::read(db)?),
+        |db, changeset| Ok(bdk_sqlite::Store::write(db, changeset)?),
     )?;
 
     Ok(())
@@ -144,10 +151,16 @@ fn load_recovers_wallet() -> anyhow::Result<()> {
 
 #[test]
 fn new_or_load() -> anyhow::Result<()> {
-    fn run<B, F>(filename: &str, new_or_load: F) -> anyhow::Result<()>
+    fn run<Db, NewOrRecover, Read, Write>(
+        filename: &str,
+        new_or_load: NewOrRecover,
+        read: Read,
+        write: Write,
+    ) -> anyhow::Result<()>
     where
-        B: PersistBackend<bdk_wallet::wallet::ChangeSet> + Send + Sync + 'static,
-        F: Fn(&Path) -> anyhow::Result<B>,
+        NewOrRecover: Fn(&Path) -> anyhow::Result<Db>,
+        Read: Fn(&mut Db) -> anyhow::Result<Option<ChangeSet>>,
+        Write: Fn(&mut Db, &ChangeSet) -> anyhow::Result<()>,
     {
         let temp_dir = tempfile::tempdir().expect("must create tempdir");
         let file_path = temp_dir.path().join(filename);
@@ -158,18 +171,16 @@ fn new_or_load() -> anyhow::Result<()> {
             let wallet = &mut Wallet::new_or_load(desc, change_desc, None, Network::Testnet)
                 .expect("must init wallet");
             let mut db = new_or_load(&file_path).expect("must create db");
-            wallet
-                .commit_to(&mut db)
-                .map_err(|e| anyhow!("write changes error: {}", e))?;
+            if let Some(changeset) = wallet.take_staged() {
+                write(&mut db, &changeset)?;
+            }
             wallet.keychains().map(|(k, v)| (*k, v.clone())).collect()
         };
 
         // wrong network
         {
             let mut db = new_or_load(&file_path).expect("must create db");
-            let changeset = db
-                .load_changes()
-                .map_err(|e| anyhow!("load changes error: {}", e))?;
+            let changeset = read(&mut db)?;
             let err = Wallet::new_or_load(desc, change_desc, changeset, Network::Bitcoin)
                 .expect_err("wrong network");
             assert!(
@@ -192,9 +203,7 @@ fn new_or_load() -> anyhow::Result<()> {
                 bitcoin::blockdata::constants::genesis_block(Network::Testnet).block_hash();
 
             let db = &mut new_or_load(&file_path).expect("must open db");
-            let changeset = db
-                .load_changes()
-                .map_err(|e| anyhow!("load changes error: {}", e))?;
+            let changeset = read(db)?;
             let err = Wallet::new_or_load_with_genesis_hash(
                 desc,
                 change_desc,
@@ -223,9 +232,7 @@ fn new_or_load() -> anyhow::Result<()> {
                 .0;
 
             let db = &mut new_or_load(&file_path).expect("must open db");
-            let changeset = db
-                .load_changes()
-                .map_err(|e| anyhow!("load changes error: {}", e))?;
+            let changeset = read(db)?;
             let err =
                 Wallet::new_or_load(exp_descriptor, exp_change_desc, changeset, Network::Testnet)
                     .expect_err("wrong external descriptor");
@@ -249,9 +256,7 @@ fn new_or_load() -> anyhow::Result<()> {
                 .0;
 
             let db = &mut new_or_load(&file_path).expect("must open db");
-            let changeset = db
-                .load_changes()
-                .map_err(|e| anyhow!("load changes error: {}", e))?;
+            let changeset = read(db)?;
             let err = Wallet::new_or_load(desc, exp_descriptor, changeset, Network::Testnet)
                 .expect_err("wrong internal descriptor");
             assert!(
@@ -268,9 +273,7 @@ fn new_or_load() -> anyhow::Result<()> {
         // all parameters match
         {
             let db = &mut new_or_load(&file_path).expect("must open db");
-            let changeset = db
-                .load_changes()
-                .map_err(|e| anyhow!("load changes error: {}", e))?;
+            let changeset = read(db)?;
             let wallet = Wallet::new_or_load(desc, change_desc, changeset, Network::Testnet)
                 .expect("must recover wallet");
             assert_eq!(wallet.network(), Network::Testnet);
@@ -282,12 +285,18 @@ fn new_or_load() -> anyhow::Result<()> {
         Ok(())
     }
 
-    run("store.db", |path| {
-        Ok(bdk_file_store::Store::open_or_create_new(DB_MAGIC, path)?)
-    })?;
-    run("store.sqlite", |path| {
-        Ok(bdk_sqlite::Store::new(Connection::open(path)?)?)
-    })?;
+    run(
+        "store.db",
+        |path| Ok(bdk_file_store::Store::open_or_create_new(DB_MAGIC, path)?),
+        |db| Ok(bdk_file_store::Store::aggregate_changesets(db)?),
+        |db, changeset| Ok(bdk_file_store::Store::append_changeset(db, changeset)?),
+    )?;
+    run(
+        "store.sqlite",
+        |path| Ok(bdk_sqlite::Store::new(Connection::open(path)?)?),
+        |db| Ok(bdk_sqlite::Store::read(db)?),
+        |db, changeset| Ok(bdk_sqlite::Store::write(db, changeset)?),
+    )?;
 
     Ok(())
 }
index 76b9ad7992f393fd8e5eb92dfd8148e9ffa74224..53969764de95e50892a0a3ad1b3a435abd1c8922 100644 (file)
@@ -11,7 +11,6 @@ use bdk_bitcoind_rpc::{
     bitcoincore_rpc::{Auth, Client, RpcApi},
     Emitter,
 };
-use bdk_chain::persist::{PersistBackend, StageExt};
 use bdk_chain::{
     bitcoin::{constants::genesis_block, Block, Transaction},
     indexed_tx_graph, keychain,
@@ -138,7 +137,7 @@ fn main() -> anyhow::Result<()> {
         let genesis_hash = genesis_block(args.network).block_hash();
         let (chain, chain_changeset) = LocalChain::from_genesis_hash(genesis_hash);
         let mut db = db.lock().unwrap();
-        db.write_changes(&(chain_changeset, Default::default()))?;
+        db.append_changeset(&(chain_changeset, Default::default()))?;
         chain
     } else {
         LocalChain::from_changeset(init_chain_changeset)?
@@ -197,7 +196,9 @@ fn main() -> anyhow::Result<()> {
                 if last_db_commit.elapsed() >= DB_COMMIT_DELAY {
                     let db = &mut *db.lock().unwrap();
                     last_db_commit = Instant::now();
-                    db_stage.commit_to(db)?;
+                    if !db_stage.is_empty() {
+                        db.append_changeset(&core::mem::take(&mut db_stage))?;
+                    }
                     println!(
                         "[{:>10}s] committed to db (took {}s)",
                         start.elapsed().as_secs_f32(),
@@ -233,10 +234,10 @@ fn main() -> anyhow::Result<()> {
             );
             {
                 let db = &mut *db.lock().unwrap();
-                db_stage.append_and_commit_to(
-                    (local_chain::ChangeSet::default(), graph_changeset),
-                    db,
-                )?;
+                db_stage.append((local_chain::ChangeSet::default(), graph_changeset));
+                if !db_stage.is_empty() {
+                    db.append_changeset(&core::mem::take(&mut db_stage))?;
+                }
             }
         }
         RpcCommands::Live { rpc_args } => {
@@ -324,7 +325,9 @@ fn main() -> anyhow::Result<()> {
                 if last_db_commit.elapsed() >= DB_COMMIT_DELAY {
                     let db = &mut *db.lock().unwrap();
                     last_db_commit = Instant::now();
-                    db_stage.commit_to(db)?;
+                    if !db_stage.is_empty() {
+                        db.append_changeset(&core::mem::take(&mut db_stage))?;
+                    }
                     println!(
                         "[{:>10}s] committed to db (took {}s)",
                         start.elapsed().as_secs_f32(),
index 6a3f432018eed09d318318e88e87561a23792ddc..b1862fb8193336276fbddb6653707cae880339f7 100644 (file)
@@ -25,7 +25,6 @@ use bdk_chain::{
 pub use bdk_file_store;
 pub use clap;
 
-use bdk_chain::persist::PersistBackend;
 use clap::{Parser, Subcommand};
 
 pub type KeychainTxGraph<A> = IndexedTxGraph<A, KeychainTxOutIndex<Keychain>>;
@@ -482,7 +481,7 @@ where
                     let ((spk_i, spk), index_changeset) =
                         spk_chooser(index, &Keychain::External).expect("Must exist");
                     let db = &mut *db.lock().unwrap();
-                    db.write_changes(&C::from((
+                    db.append_changeset(&C::from((
                         local_chain::ChangeSet::default(),
                         indexed_tx_graph::ChangeSet::from(index_changeset),
                     )))?;
@@ -630,7 +629,7 @@ where
                     // If we're unable to persist this, then we don't want to broadcast.
                     {
                         let db = &mut *db.lock().unwrap();
-                        db.write_changes(&C::from((
+                        db.append_changeset(&C::from((
                             local_chain::ChangeSet::default(),
                             indexed_tx_graph::ChangeSet::from(index_changeset),
                         )))?;
@@ -655,7 +654,7 @@ where
                     // We know the tx is at least unconfirmed now. Note if persisting here fails,
                     // it's not a big deal since we can always find it again form
                     // blockchain.
-                    db.lock().unwrap().write_changes(&C::from((
+                    db.lock().unwrap().append_changeset(&C::from((
                         local_chain::ChangeSet::default(),
                         keychain_changeset,
                     )))?;
@@ -736,7 +735,7 @@ where
         Err(err) => return Err(anyhow::anyhow!("failed to init db backend: {:?}", err)),
     };
 
-    let init_changeset = db_backend.load_changes()?.unwrap_or_default();
+    let init_changeset = db_backend.aggregate_changesets()?.unwrap_or_default();
 
     Ok(Init {
         args,
index 2b77e97c4927792c14610a0900794ba22c06ad3a..4789269dd559574f9aa37f6b1b8eefa2f565bf80 100644 (file)
@@ -3,7 +3,6 @@ use std::{
     sync::Mutex,
 };
 
-use bdk_chain::persist::PersistBackend;
 use bdk_chain::{
     bitcoin::{constants::genesis_block, Address, Network, Txid},
     collections::BTreeSet,
@@ -352,6 +351,6 @@ fn main() -> anyhow::Result<()> {
     };
 
     let mut db = db.lock().unwrap();
-    db.write_changes(&db_changeset)?;
+    db.append_changeset(&db_changeset)?;
     Ok(())
 }
index 13e6e6abb3bd4484655e4ab6c236fe9d082dfc7e..3f9b872103ece3c0aa0cd612b18b87fbf7d81373 100644 (file)
@@ -4,7 +4,6 @@ use std::{
     sync::Mutex,
 };
 
-use bdk_chain::persist::PersistBackend;
 use bdk_chain::{
     bitcoin::{constants::genesis_block, Address, Network, Txid},
     indexed_tx_graph::{self, IndexedTxGraph},
@@ -362,6 +361,6 @@ fn main() -> anyhow::Result<()> {
 
     // We persist the changes
     let mut db = db.lock().unwrap();
-    db.write_changes(&(local_chain_changeset, indexed_tx_graph_changeset))?;
+    db.append_changeset(&(local_chain_changeset, indexed_tx_graph_changeset))?;
     Ok(())
 }
index c7c563c1522079f25772c60db12b02c849784f15..2adf090aa667d9194a6774d1e0161b9a0787b6d9 100644 (file)
@@ -12,7 +12,6 @@ use bdk_electrum::BdkElectrumClient;
 use bdk_file_store::Store;
 use bdk_wallet::bitcoin::{Address, Amount};
 use bdk_wallet::chain::collections::HashSet;
-use bdk_wallet::chain::persist::PersistBackend;
 use bdk_wallet::{bitcoin::Network, Wallet};
 use bdk_wallet::{KeychainKind, SignOptions};
 
@@ -23,7 +22,7 @@ fn main() -> Result<(), anyhow::Error> {
     let external_descriptor = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/1'/0'/0/*)";
     let internal_descriptor = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/1'/0'/1/*)";
     let changeset = db
-        .load_changes()
+        .aggregate_changesets()
         .map_err(|e| anyhow!("load changes error: {}", e))?;
     let mut wallet = Wallet::new_or_load(
         external_descriptor,
@@ -33,7 +32,9 @@ fn main() -> Result<(), anyhow::Error> {
     )?;
 
     let address = wallet.next_unused_address(KeychainKind::External);
-    wallet.commit_to(&mut db)?;
+    if let Some(changeset) = wallet.take_staged() {
+        db.append_changeset(&changeset)?;
+    }
     println!("Generated Address: {}", address);
 
     let balance = wallet.balance();
@@ -72,7 +73,9 @@ fn main() -> Result<(), anyhow::Error> {
     println!();
 
     wallet.apply_update(update)?;
-    wallet.commit_to(&mut db)?;
+    if let Some(changeset) = wallet.take_staged() {
+        db.append_changeset(&changeset)?;
+    }
 
     let balance = wallet.balance();
     println!("Wallet balance after syncing: {} sats", balance.total());
index 6a666d49bab2c7e23ede4308ec7f356cfe3330f1..0fd82b98594ce3e0b9f63cacf5ac8ad6089241b0 100644 (file)
@@ -7,7 +7,6 @@ use bdk_wallet::{
 };
 
 use bdk_sqlite::{rusqlite::Connection, Store};
-use bdk_wallet::chain::persist::PersistBackend;
 
 const SEND_AMOUNT: Amount = Amount::from_sat(5000);
 const STOP_GAP: usize = 50;
@@ -20,7 +19,7 @@ async fn main() -> Result<(), anyhow::Error> {
     let mut db = Store::new(conn)?;
     let external_descriptor = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/1'/0'/0/*)";
     let internal_descriptor = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/1'/0'/1/*)";
-    let changeset = db.load_changes()?;
+    let changeset = db.read()?;
 
     let mut wallet = Wallet::new_or_load(
         external_descriptor,
@@ -30,7 +29,9 @@ async fn main() -> Result<(), anyhow::Error> {
     )?;
 
     let address = wallet.next_unused_address(KeychainKind::External);
-    wallet.commit_to(&mut db)?;
+    if let Some(changeset) = wallet.take_staged() {
+        db.write(&changeset)?;
+    }
     println!("Generated Address: {}", address);
 
     let balance = wallet.balance();
@@ -78,7 +79,9 @@ async fn main() -> Result<(), anyhow::Error> {
     let _ = update.graph_update.update_last_seen_unconfirmed(now);
 
     wallet.apply_update(update)?;
-    wallet.commit_to(&mut db)?;
+    if let Some(changeset) = wallet.take_staged() {
+        db.write(&changeset)?;
+    }
     println!();
 
     let balance = wallet.balance();
index 21e9fe68849a9ea6aead003a1fad33f726d23283..32211b04bf69c31fdc729004267e82d2b402ed38 100644 (file)
@@ -7,7 +7,6 @@ use std::{collections::BTreeSet, io::Write, str::FromStr};
 
 use bdk_esplora::{esplora_client, EsploraExt};
 use bdk_file_store::Store;
-use bdk_wallet::chain::persist::PersistBackend;
 use bdk_wallet::{
     bitcoin::{Address, Amount, Network},
     KeychainKind, SignOptions, Wallet,
@@ -19,7 +18,7 @@ fn main() -> Result<(), anyhow::Error> {
         Store::<bdk_wallet::wallet::ChangeSet>::open_or_create_new(DB_MAGIC.as_bytes(), db_path)?;
     let external_descriptor = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/1'/0'/0/*)";
     let internal_descriptor = "wpkh(tprv8ZgxMBicQKsPdy6LMhUtFHAgpocR8GC6QmwMSFpZs7h6Eziw3SpThFfczTDh5rW2krkqffa11UpX3XkeTTB2FvzZKWXqPY54Y6Rq4AQ5R8L/84'/1'/0'/1/*)";
-    let changeset = db.load_changes()?;
+    let changeset = db.aggregate_changesets()?;
 
     let mut wallet = Wallet::new_or_load(
         external_descriptor,
@@ -29,7 +28,9 @@ fn main() -> Result<(), anyhow::Error> {
     )?;
 
     let address = wallet.next_unused_address(KeychainKind::External);
-    wallet.commit_to(&mut db)?;
+    if let Some(changeset) = wallet.take_staged() {
+        db.append_changeset(&changeset)?;
+    }
     println!("Generated Address: {}", address);
 
     let balance = wallet.balance();
@@ -55,7 +56,9 @@ fn main() -> Result<(), anyhow::Error> {
     let _ = update.graph_update.update_last_seen_unconfirmed(now);
 
     wallet.apply_update(update)?;
-    wallet.commit_to(&mut db)?;
+    if let Some(changeset) = wallet.take_staged() {
+        db.append_changeset(&changeset)?;
+    }
     println!();
 
     let balance = wallet.balance();
index e0d617493ff4d80e60b367f50be216eb31a13a7a..e09e6d7623e0ce04a0baa6710f04fe6aa0489a58 100644 (file)
@@ -3,7 +3,6 @@ use bdk_bitcoind_rpc::{
     Emitter,
 };
 use bdk_file_store::Store;
-use bdk_wallet::chain::persist::PersistBackend;
 use bdk_wallet::{
     bitcoin::{Block, Network, Transaction},
     wallet::Wallet,
@@ -91,7 +90,7 @@ fn main() -> anyhow::Result<()> {
         DB_MAGIC.as_bytes(),
         args.db_path,
     )?;
-    let changeset = db.load_changes()?;
+    let changeset = db.aggregate_changesets()?;
 
     let mut wallet = Wallet::new_or_load(
         &args.descriptor,
@@ -147,7 +146,9 @@ fn main() -> anyhow::Result<()> {
                 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.commit_to(&mut db)?;
+                if let Some(changeset) = wallet.take_staged() {
+                    db.append_changeset(&changeset)?;
+                }
                 let elapsed = start_apply_block.elapsed().as_secs_f32();
                 println!(
                     "Applied block {} at height {} in {}s",
@@ -157,7 +158,9 @@ fn main() -> anyhow::Result<()> {
             Emission::Mempool(mempool_emission) => {
                 let start_apply_mempool = Instant::now();
                 wallet.apply_unconfirmed_txs(mempool_emission.iter().map(|(tx, time)| (tx, *time)));
-                wallet.commit_to(&mut db)?;
+                if let Some(changeset) = wallet.take_staged() {
+                    db.append_changeset(&changeset)?;
+                }
                 println!(
                     "Applied unconfirmed transactions in {}s",
                     start_apply_mempool.elapsed().as_secs_f32()