Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
97 changes: 95 additions & 2 deletions crates/wallet/src/wallet/changeset.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,105 @@ use bdk_chain::{
indexed_tx_graph, keychain_txout, local_chain, tx_graph, ConfirmationBlockTime, Merge,
};
use miniscript::{Descriptor, DescriptorPublicKey};
use serde::{Deserialize, Serialize};

type IndexedTxGraphChangeSet =
indexed_tx_graph::ChangeSet<ConfirmationBlockTime, keychain_txout::ChangeSet>;

/// A changeset for [`Wallet`](crate::Wallet).
#[derive(Default, Debug, Clone, PartialEq, serde::Deserialize, serde::Serialize)]
/// A change set for [`Wallet`]
///
/// ## Definition
///
/// The change set is responsible for transmiting data between the persistent storage layer and the
/// core library components. Specifically, it serves two primary functions:
///
/// 1) Recording incremental changes to the in-memory representation that need to be persisted
/// to disk
/// 2) Applying aggregate changes from the persistence layer to the in-memory representation at
/// startup
///
/// ## Contract
///
/// The change set maintains and enforces the following properties:
///
/// * Change sets must implement [`Serialize`] and [`Deserialize`] to meet the definition from
/// above.
/// * Change sets must implement [`Default`] as a way of instantiating new empty objects.
/// * Change sets must implement [`Merge`] so that many instances can be aggregated into a single
/// instance.
/// * A change set is composed of a number of individual "sub-change sets" that adhere to the same
/// rules as above. This is for increased modularity and portability. For example the core
/// modules each have their own change set (`tx_graph`, `local_chain`, etc).
///
/// ## Members and required fields
///
/// The change set has certain required fields without which a `Wallet` cannot function.
/// These include the [`descriptor`] and the [`network`] in use. These are required to be non-empty
/// *in the aggregate*, meaning the field must be present and non-null in the union of all
/// persisted changes, but may be empty in any one change set, where "empty" is defined by the
/// [`Merge`](Merge::is_empty) implementation of that change set. This requirement also applies to
/// the [`local_chain`] field in that the aggregate change set must include a genesis block.
///
/// For example, the descriptor and network are present in the first change set after wallet
/// creation, but are usually omitted in subsequent updates, as they are not permitted to change
/// at any point thereafter.
///
/// Other fields of the change set are not required to be non-empty, that is they may be empty even
/// in the aggregate. However in practice they should contain the data needed to recover a wallet
/// state between sessions. These include:
/// * [`tx_graph`](Self::tx_graph)
/// * [`indexer`](Self::indexer)
///
/// The [`change_descriptor`] is special in that its presence is optional, however the value of the
/// change descriptor should be defined at wallet creation time and respected for the life of the
/// wallet, meaning that if a change descriptor is originally defined, it must also be present in
/// the aggregate change set.
///
/// ## Staging
///
/// For greater efficiency the [`Wallet`] is able to *stage* the to-be-persisted changes. Many
/// operations result in staged changes which require persistence on the part of the user. These
/// include address revelation, applying an [`Update`], and introducing transactions and chain
/// data to the wallet. To get the staged changes see [`Wallet::staged`] and similar methods. Once
/// the changes are committed to the persistence layer the contents of the stage should be
/// discarded.
///
/// Users should persist early and often generally speaking, however in principle there is no
/// limit to the number or type of changes that can be staged prior to persisting or the order in
/// which they're staged. This is because change sets are designed to be [merged]. The change
/// that is ultimately persisted will encompass the combined effect of each change individually.
///
/// ## Extensibility
///
/// Existing fields may be extended in the future with additional sub-fields. New top-level fields
/// are likely to be added as new features and core components are implemented. Existing fields may
/// be removed in future versions of the library.
///
/// The authors reserve the right to make breaking changes to the [`ChangeSet`] structure in
/// a major version release. API changes affecting the types of data persisted will display
/// prominently in the release notes. Users are advised to look for such changes and update their
/// application accordingly.
///
/// The resulting interface is designed to give the user more control of what to persist and when
/// to persist it. Custom implementations should consider and account for the possibility of
/// partial or repeat writes, the atomicity of persistence operations, and the order of reads and
/// writes among the fields of the change set. BDK comes with support for [SQLite] that handles
/// the details for you and is recommended for many users. If implementing your own persistence,
/// please refer to the documentation for [`WalletPersister`] and [`PersistedWallet`] for more
/// information.
///
/// [`change_descriptor`]: Self::change_descriptor
/// [`descriptor`]: Self::descriptor
/// [`local_chain`]: Self::local_chain
/// [merged]: bdk_chain::Merge
/// [`network`]: Self::network
/// [`PersistedWallet`]: crate::PersistedWallet
/// [SQLite]: bdk_chain::rusqlite_impl
/// [`Update`]: crate::Update
/// [`WalletPersister`]: crate::WalletPersister
/// [`Wallet::staged`]: crate::Wallet::staged
/// [`Wallet`]: crate::Wallet
#[derive(Default, Debug, Clone, PartialEq, Deserialize, Serialize)]
pub struct ChangeSet {
/// Descriptor for recipient addresses.
pub descriptor: Option<Descriptor<DescriptorPublicKey>>,
Expand Down
2 changes: 1 addition & 1 deletion crates/wallet/src/wallet/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -478,7 +478,7 @@ impl Wallet {

/// Load [`Wallet`] from the given previously persisted [`ChangeSet`] and `params`.
///
/// Refer to [`Wallet::load`] for more.
/// Returns `Ok(None)` if the changeset is empty. Refer to [`Wallet::load`] for more.
pub fn load_with_params(
changeset: ChangeSet,
params: LoadParams,
Expand Down
Loading