feat!: Rework sqlite, changesets, persistence and wallet-construction
Rework sqlite: Instead of only supported one schema (defined in `bdk_sqlite`), we have a schema per changeset type for more flexiblity. * rm `bdk_sqlite` crate (as we don't need `bdk_sqlite::Store` anymore). * add `sqlite` feature on `bdk_chain` which adds methods on each changeset type for initializing tables, loading the changeset and writing. Rework changesets: Some callers may want to use `KeychainTxOutIndex` where `K` may change per descriptor on every run. So we only want to persist the last revealed indices by `DescriptorId` (which uniquely-ish identifies the descriptor). * rm `keychain_added` field from `keychain_txout`'s changeset. * Add `keychain_added` to `CombinedChangeSet` (which is renamed to `WalletChangeSet`). Rework persistence: add back some safety and convenience when persisting our types. Working with changeset directly (as we were doing before) can be cumbersome. * Intoduce `struct Persisted<T>` which wraps a type `T` which stores staged changes to it. This adds safety when creating and or loading `T` from db. * `struct Persisted<T>` methods, `create`, `load` and `persist`, are avaliable if `trait PersistWith<Db>` is implemented for `T`. `Db` represents the database connection and `PersistWith` should be implemented per database-type. * For async, we have `trait PersistedAsyncWith<Db>`. * `Wallet` has impls of `PersistedWith<rusqlite::Connection>`, `PersistedWith<rusqlite::Transaction>` and `PersistedWith<bdk_file_store::Store>` by default. Rework wallet-construction: Before, we had multiple methods for loading and creating with different input-counts so it would be unwieldly to add more parameters in the future. This also makes it difficult to impl `PersistWith` (which has a single method for `load` that takes in `PersistWith::LoadParams` and a single method for `create` that takes in `PersistWith::CreateParams`). * Introduce a builder pattern when constructing a `Wallet`. For loading from persistence or `ChangeSet`, we have `LoadParams`. For creating a new wallet, we have `CreateParams`.
This commit is contained in:
@@ -1,5 +1,7 @@
|
||||
//! Contains the [`IndexedTxGraph`] and associated types. Refer to the
|
||||
//! [`IndexedTxGraph`] documentation for more.
|
||||
use core::fmt::Debug;
|
||||
|
||||
use alloc::vec::Vec;
|
||||
use bitcoin::{Block, OutPoint, Transaction, TxOut, Txid};
|
||||
|
||||
@@ -47,21 +49,24 @@ impl<A: Anchor, I: Indexer> IndexedTxGraph<A, I> {
|
||||
pub fn apply_changeset(&mut self, changeset: ChangeSet<A, I::ChangeSet>) {
|
||||
self.index.apply_changeset(changeset.indexer);
|
||||
|
||||
for tx in &changeset.graph.txs {
|
||||
for tx in &changeset.tx_graph.txs {
|
||||
self.index.index_tx(tx);
|
||||
}
|
||||
for (&outpoint, txout) in &changeset.graph.txouts {
|
||||
for (&outpoint, txout) in &changeset.tx_graph.txouts {
|
||||
self.index.index_txout(outpoint, txout);
|
||||
}
|
||||
|
||||
self.graph.apply_changeset(changeset.graph);
|
||||
self.graph.apply_changeset(changeset.tx_graph);
|
||||
}
|
||||
|
||||
/// Determines the [`ChangeSet`] between `self` and an empty [`IndexedTxGraph`].
|
||||
pub fn initial_changeset(&self) -> ChangeSet<A, I::ChangeSet> {
|
||||
let graph = self.graph.initial_changeset();
|
||||
let indexer = self.index.initial_changeset();
|
||||
ChangeSet { graph, indexer }
|
||||
ChangeSet {
|
||||
tx_graph: graph,
|
||||
indexer,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -89,21 +94,30 @@ where
|
||||
pub fn apply_update(&mut self, update: TxGraph<A>) -> ChangeSet<A, I::ChangeSet> {
|
||||
let graph = self.graph.apply_update(update);
|
||||
let indexer = self.index_tx_graph_changeset(&graph);
|
||||
ChangeSet { graph, indexer }
|
||||
ChangeSet {
|
||||
tx_graph: graph,
|
||||
indexer,
|
||||
}
|
||||
}
|
||||
|
||||
/// Insert a floating `txout` of given `outpoint`.
|
||||
pub fn insert_txout(&mut self, outpoint: OutPoint, txout: TxOut) -> ChangeSet<A, I::ChangeSet> {
|
||||
let graph = self.graph.insert_txout(outpoint, txout);
|
||||
let indexer = self.index_tx_graph_changeset(&graph);
|
||||
ChangeSet { graph, indexer }
|
||||
ChangeSet {
|
||||
tx_graph: graph,
|
||||
indexer,
|
||||
}
|
||||
}
|
||||
|
||||
/// Insert and index a transaction into the graph.
|
||||
pub fn insert_tx(&mut self, tx: Transaction) -> ChangeSet<A, I::ChangeSet> {
|
||||
let graph = self.graph.insert_tx(tx);
|
||||
let indexer = self.index_tx_graph_changeset(&graph);
|
||||
ChangeSet { graph, indexer }
|
||||
ChangeSet {
|
||||
tx_graph: graph,
|
||||
indexer,
|
||||
}
|
||||
}
|
||||
|
||||
/// Insert an `anchor` for a given transaction.
|
||||
@@ -151,7 +165,10 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
ChangeSet { graph, indexer }
|
||||
ChangeSet {
|
||||
tx_graph: graph,
|
||||
indexer,
|
||||
}
|
||||
}
|
||||
|
||||
/// Batch insert unconfirmed transactions, filtering out those that are irrelevant.
|
||||
@@ -185,7 +202,10 @@ where
|
||||
.map(|(tx, seen_at)| (tx.clone(), seen_at)),
|
||||
);
|
||||
|
||||
ChangeSet { graph, indexer }
|
||||
ChangeSet {
|
||||
tx_graph: graph,
|
||||
indexer,
|
||||
}
|
||||
}
|
||||
|
||||
/// Batch insert unconfirmed transactions.
|
||||
@@ -203,7 +223,10 @@ where
|
||||
) -> ChangeSet<A, I::ChangeSet> {
|
||||
let graph = self.graph.batch_insert_unconfirmed(txs);
|
||||
let indexer = self.index_tx_graph_changeset(&graph);
|
||||
ChangeSet { graph, indexer }
|
||||
ChangeSet {
|
||||
tx_graph: graph,
|
||||
indexer,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -236,9 +259,9 @@ where
|
||||
if self.index.is_tx_relevant(tx) {
|
||||
let txid = tx.compute_txid();
|
||||
let anchor = A::from_block_position(block, block_id, tx_pos);
|
||||
changeset.graph.merge(self.graph.insert_tx(tx.clone()));
|
||||
changeset.tx_graph.merge(self.graph.insert_tx(tx.clone()));
|
||||
changeset
|
||||
.graph
|
||||
.tx_graph
|
||||
.merge(self.graph.insert_anchor(txid, anchor));
|
||||
}
|
||||
}
|
||||
@@ -265,7 +288,16 @@ where
|
||||
graph.merge(self.graph.insert_tx(tx.clone()));
|
||||
}
|
||||
let indexer = self.index_tx_graph_changeset(&graph);
|
||||
ChangeSet { graph, indexer }
|
||||
ChangeSet {
|
||||
tx_graph: graph,
|
||||
indexer,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, I> AsRef<TxGraph<A>> for IndexedTxGraph<A, I> {
|
||||
fn as_ref(&self) -> &TxGraph<A> {
|
||||
&self.graph
|
||||
}
|
||||
}
|
||||
|
||||
@@ -285,7 +317,7 @@ where
|
||||
#[must_use]
|
||||
pub struct ChangeSet<A, IA> {
|
||||
/// [`TxGraph`] changeset.
|
||||
pub graph: tx_graph::ChangeSet<A>,
|
||||
pub tx_graph: tx_graph::ChangeSet<A>,
|
||||
/// [`Indexer`] changeset.
|
||||
pub indexer: IA,
|
||||
}
|
||||
@@ -293,7 +325,7 @@ pub struct ChangeSet<A, IA> {
|
||||
impl<A, IA: Default> Default for ChangeSet<A, IA> {
|
||||
fn default() -> Self {
|
||||
Self {
|
||||
graph: Default::default(),
|
||||
tx_graph: Default::default(),
|
||||
indexer: Default::default(),
|
||||
}
|
||||
}
|
||||
@@ -301,38 +333,30 @@ impl<A, IA: Default> Default for ChangeSet<A, IA> {
|
||||
|
||||
impl<A: Anchor, IA: Merge> Merge for ChangeSet<A, IA> {
|
||||
fn merge(&mut self, other: Self) {
|
||||
self.graph.merge(other.graph);
|
||||
self.tx_graph.merge(other.tx_graph);
|
||||
self.indexer.merge(other.indexer);
|
||||
}
|
||||
|
||||
fn is_empty(&self) -> bool {
|
||||
self.graph.is_empty() && self.indexer.is_empty()
|
||||
self.tx_graph.is_empty() && self.indexer.is_empty()
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, IA: Default> From<tx_graph::ChangeSet<A>> for ChangeSet<A, IA> {
|
||||
fn from(graph: tx_graph::ChangeSet<A>) -> Self {
|
||||
Self {
|
||||
graph,
|
||||
tx_graph: graph,
|
||||
..Default::default()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "miniscript")]
|
||||
impl<A, K> From<crate::indexer::keychain_txout::ChangeSet<K>>
|
||||
for ChangeSet<A, crate::indexer::keychain_txout::ChangeSet<K>>
|
||||
{
|
||||
fn from(indexer: crate::indexer::keychain_txout::ChangeSet<K>) -> Self {
|
||||
impl<A> From<crate::keychain_txout::ChangeSet> for ChangeSet<A, crate::keychain_txout::ChangeSet> {
|
||||
fn from(indexer: crate::keychain_txout::ChangeSet) -> Self {
|
||||
Self {
|
||||
graph: Default::default(),
|
||||
tx_graph: Default::default(),
|
||||
indexer,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<A, I> AsRef<TxGraph<A>> for IndexedTxGraph<A, I> {
|
||||
fn as_ref(&self) -> &TxGraph<A> {
|
||||
&self.graph
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user