Merge bitcoindevkit/bdk#1387: fix(wallet): remove the generic from wallet

e51af49ffa fix(wallet): remove generic from wallet (Rob N)

Pull request description:

  ### Description

  The `PersistenceBackend` uses generics to describe errors returned while applying the change set to the persistence layer. This change removes generics wherever possible and introduces a new public error enum. Removing the generics from `PersistenceBackend` errors is the first step towards #1363

  *Update*: I proceeded with removing the generics from `Wallet` by introducing a `Box<dyn PersistenceBackend>` .

  ### Notes to the reviewers

  This one sort of blew up in the number of changes due to the use of generics for most of the `Wallet` error variants. The generics were only used for the persistence errors, so I removed the generics from higher level errors whenever possible. The error variants of `PersistenceBackend` may also be more expressive, but I will level that up for discussion and make any changes required.

  ### Changelog notice

  - Changed `PersistenceBackend` errors to depend on the `anyhow` crate.
  - Remove the generic `T` from `Wallet`

  ### Checklists

  #### All Submissions:

  * [x] I've signed all my commits
  * [x] I followed the [contribution guidelines](https://github.com/bitcoindevkit/bdk/blob/master/CONTRIBUTING.md)
  * [x] I ran `cargo fmt` and `cargo clippy` before committing

  #### New Features:

  * [ ] I've added tests for the new feature
  * [x] I've added docs for the new feature

  #### Bugfixes:

  * [x] This pull request breaks the existing API
  * [ ] I've added tests to reproduce the issue which are now passing
  * [x] I'm linking the issue being fixed by this PR

ACKs for top commit:
  evanlinjin:
    ACK e51af49ffa

Tree-SHA512: 8ce4f1c495310e16145555f4a6a29a0f42cf8944eda68004595c3532580767f64f779185022147a00d75001c40d69fdf8f8de2d348eb68484b170d2a181117ff
This commit is contained in:
志宇
2024-04-20 14:51:26 +08:00
10 changed files with 157 additions and 234 deletions

View File

@@ -14,6 +14,7 @@ readme = "README.md"
[dependencies]
# For no-std, remember to enable the bitcoin/no-std feature
anyhow = { version = "1", default-features = false }
bitcoin = { version = "0.31.0", default-features = false }
serde_crate = { package = "serde", version = "1", optional = true, features = ["derive", "rc"] }

View File

@@ -1,26 +1,32 @@
use core::convert::Infallible;
use crate::Append;
use alloc::boxed::Box;
use core::fmt;
/// `Persist` wraps a [`PersistBackend`] (`B`) to create a convenient staging area for changes (`C`)
/// `Persist` wraps a [`PersistBackend`] to create a convenient staging area for changes (`C`)
/// before they are persisted.
///
/// Not all changes to the in-memory representation needs to be written to disk right away, so
/// [`Persist::stage`] can be used to *stage* changes first and then [`Persist::commit`] can be used
/// to write changes to disk.
#[derive(Debug)]
pub struct Persist<B, C> {
backend: B,
pub struct Persist<C> {
backend: Box<dyn PersistBackend<C> + Send + Sync>,
stage: C,
}
impl<B, C> Persist<B, C>
impl<C: fmt::Debug> fmt::Debug for Persist<C> {
fn fmt(&self, fmt: &mut core::fmt::Formatter<'_>) -> Result<(), core::fmt::Error> {
write!(fmt, "{:?}", self.stage)?;
Ok(())
}
}
impl<C> Persist<C>
where
B: PersistBackend<C>,
C: Default + Append,
{
/// Create a new [`Persist`] from [`PersistBackend`].
pub fn new(backend: B) -> Self {
pub fn new(backend: impl PersistBackend<C> + Send + Sync + 'static) -> Self {
let backend = Box::new(backend);
Self {
backend,
stage: Default::default(),
@@ -46,7 +52,7 @@ where
/// # Error
///
/// Returns a backend-defined error if this fails.
pub fn commit(&mut self) -> Result<Option<C>, B::WriteError> {
pub fn commit(&mut self) -> anyhow::Result<Option<C>> {
if self.stage.is_empty() {
return Ok(None);
}
@@ -63,7 +69,7 @@ where
///
/// [`stage`]: Self::stage
/// [`commit`]: Self::commit
pub fn stage_and_commit(&mut self, changeset: C) -> Result<Option<C>, B::WriteError> {
pub fn stage_and_commit(&mut self, changeset: C) -> anyhow::Result<Option<C>> {
self.stage(changeset);
self.commit()
}
@@ -74,12 +80,6 @@ where
/// `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: core::fmt::Debug;
/// The error the backend returns when it fails to load changesets `C`.
type LoadError: core::fmt::Debug;
/// 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
@@ -88,22 +88,18 @@ pub trait PersistBackend<C> {
/// changesets had been applied sequentially.
///
/// [`load_from_persistence`]: Self::load_from_persistence
fn write_changes(&mut self, changeset: &C) -> Result<(), Self::WriteError>;
fn write_changes(&mut self, changeset: &C) -> anyhow::Result<()>;
/// Return the aggregate changeset `C` from persistence.
fn load_from_persistence(&mut self) -> Result<Option<C>, Self::LoadError>;
fn load_from_persistence(&mut self) -> anyhow::Result<Option<C>>;
}
impl<C> PersistBackend<C> for () {
type WriteError = Infallible;
type LoadError = Infallible;
fn write_changes(&mut self, _changeset: &C) -> Result<(), Self::WriteError> {
fn write_changes(&mut self, _changeset: &C) -> anyhow::Result<()> {
Ok(())
}
fn load_from_persistence(&mut self) -> Result<Option<C>, Self::LoadError> {
fn load_from_persistence(&mut self) -> anyhow::Result<Option<C>> {
Ok(None)
}
}