Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

refactor(wallet)!: rework persistence, changeset, and construction #1514

Merged
merged 10 commits into from
Jul 22, 2024
Merged
1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ members = [
"crates/wallet",
"crates/chain",
"crates/file_store",
"crates/sqlite",
"crates/electrum",
"crates/esplora",
"crates/bitcoind_rpc",
Expand Down
25 changes: 14 additions & 11 deletions crates/bitcoind_rpc/tests/test_emitter.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ use bdk_bitcoind_rpc::Emitter;
use bdk_chain::{
bitcoin::{Address, Amount, Txid},
local_chain::{CheckPoint, LocalChain},
Balance, BlockId, IndexedTxGraph, Merge, SpkTxOutIndex,
spk_txout::SpkTxOutIndex,
Balance, BlockId, IndexedTxGraph, Merge,
};
use bdk_testenv::{anyhow, TestEnv};
use bitcoin::{hashes::Hash, Block, OutPoint, ScriptBuf, WScriptHash};
Expand Down Expand Up @@ -47,7 +48,7 @@ pub fn test_sync_local_chain() -> anyhow::Result<()> {

assert_eq!(
local_chain.apply_update(emission.checkpoint,)?,
BTreeMap::from([(height, Some(hash))]),
[(height, Some(hash))].into(),
"chain update changeset is unexpected",
);
}
Expand Down Expand Up @@ -93,11 +94,13 @@ pub fn test_sync_local_chain() -> anyhow::Result<()> {
assert_eq!(
local_chain.apply_update(emission.checkpoint,)?,
if exp_height == exp_hashes.len() - reorged_blocks.len() {
core::iter::once((height, Some(hash)))
.chain((height + 1..exp_hashes.len() as u32).map(|h| (h, None)))
.collect::<bdk_chain::local_chain::ChangeSet>()
bdk_chain::local_chain::ChangeSet {
blocks: core::iter::once((height, Some(hash)))
.chain((height + 1..exp_hashes.len() as u32).map(|h| (h, None)))
.collect(),
}
} else {
BTreeMap::from([(height, Some(hash))])
[(height, Some(hash))].into()
},
"chain update changeset is unexpected",
);
Expand Down Expand Up @@ -193,15 +196,15 @@ fn test_into_tx_graph() -> anyhow::Result<()> {
let indexed_additions = indexed_tx_graph.batch_insert_unconfirmed(mempool_txs);
assert_eq!(
indexed_additions
.graph
.tx_graph
.txs
.iter()
.map(|tx| tx.compute_txid())
.collect::<BTreeSet<Txid>>(),
exp_txids,
"changeset should have the 3 mempool transactions",
);
assert!(indexed_additions.graph.anchors.is_empty());
assert!(indexed_additions.tx_graph.anchors.is_empty());
}

// mine a block that confirms the 3 txs
Expand All @@ -224,9 +227,9 @@ fn test_into_tx_graph() -> anyhow::Result<()> {
let height = emission.block_height();
let _ = chain.apply_update(emission.checkpoint)?;
let indexed_additions = indexed_tx_graph.apply_block_relevant(&emission.block, height);
assert!(indexed_additions.graph.txs.is_empty());
assert!(indexed_additions.graph.txouts.is_empty());
assert_eq!(indexed_additions.graph.anchors, exp_anchors);
assert!(indexed_additions.tx_graph.txs.is_empty());
assert!(indexed_additions.tx_graph.txouts.is_empty());
assert_eq!(indexed_additions.tx_graph.anchors, exp_anchors);
}

Ok(())
Expand Down
5 changes: 5 additions & 0 deletions crates/chain/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@ serde_crate = { package = "serde", version = "1", optional = true, features = ["
hashbrown = { version = "0.9.1", optional = true, features = ["serde"] }
miniscript = { version = "12.0.0", optional = true, default-features = false }

# Feature dependencies
rusqlite_crate = { package = "rusqlite", version = "0.31.0", features = ["bundled"], optional = true }
serde_json = {version = "1", optional = true }

[dev-dependencies]
rand = "0.8"
proptest = "1.2.0"
Expand All @@ -28,3 +32,4 @@ proptest = "1.2.0"
default = ["std", "miniscript"]
std = ["bitcoin/std", "miniscript?/std"]
serde = ["serde_crate", "bitcoin/serde", "miniscript?/serde"]
rusqlite = ["std", "rusqlite_crate", "serde", "serde_json"]
93 changes: 0 additions & 93 deletions crates/chain/src/changeset.rs

This file was deleted.

82 changes: 53 additions & 29 deletions crates/chain/src/indexed_tx_graph.rs
Original file line number Diff line number Diff line change
@@ -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};

Expand Down Expand Up @@ -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();
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⛏️ small nit.

Suggested change
let graph = self.graph.initial_changeset();
let tx_graph = self.graph.initial_changeset();

let indexer = self.index.initial_changeset();
ChangeSet { graph, indexer }
ChangeSet {
tx_graph: graph,
indexer,
}
}
}

Expand Down Expand Up @@ -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);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⛏️ same small nit.

Suggested change
let graph = self.graph.apply_update(update);
let tx_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);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⛏️ same nit.

Suggested change
let graph = self.graph.insert_txout(outpoint, txout);
let tx_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);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⛏️ nit and same for rest of file.

Suggested change
let graph = self.graph.insert_tx(tx);
let tx_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.
Expand Down Expand Up @@ -151,7 +165,10 @@ where
}
}

ChangeSet { graph, indexer }
ChangeSet {
tx_graph: graph,
indexer,
}
}

/// Batch insert unconfirmed transactions, filtering out those that are irrelevant.
Expand Down Expand Up @@ -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.
Expand All @@ -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,
}
}
}

Expand Down Expand Up @@ -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));
}
}
Expand All @@ -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
}
}

Expand All @@ -285,54 +317,46 @@ 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,
}

impl<A, IA: Default> Default for ChangeSet<A, IA> {
fn default() -> Self {
Self {
graph: Default::default(),
tx_graph: Default::default(),
indexer: Default::default(),
}
}
}

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
}
}
Loading
Loading