refactor: move WalletChangeset to wallet module

Consequently, remove the `WalletChangeset` dependency from
`example_electrum` and `example_esplora` examples.
This commit is contained in:
Vladimir Fomene 2023-08-21 15:18:16 +03:00 committed by 志宇
parent 2392e50fd9
commit 68572bfd2e
No known key found for this signature in database
GPG Key ID: F6345C9837C2BDE8
5 changed files with 98 additions and 93 deletions

View File

@ -22,10 +22,10 @@ use alloc::{
pub use bdk_chain::keychain::Balance; pub use bdk_chain::keychain::Balance;
use bdk_chain::{ use bdk_chain::{
indexed_tx_graph, indexed_tx_graph,
keychain::{KeychainTxOutIndex, WalletChangeSet}, keychain::{self, KeychainTxOutIndex},
local_chain::{self, CannotConnectError, CheckPoint, CheckPointIter, LocalChain}, local_chain::{self, CannotConnectError, CheckPoint, CheckPointIter, LocalChain},
tx_graph::{CanonicalTx, TxGraph}, tx_graph::{CanonicalTx, TxGraph},
Append, BlockId, ChainPosition, ConfirmationTime, ConfirmationTimeAnchor, FullTxOut, Anchor, Append, BlockId, ChainPosition, ConfirmationTime, ConfirmationTimeAnchor, FullTxOut,
IndexedTxGraph, Persist, PersistBackend, IndexedTxGraph, Persist, PersistBackend,
}; };
use bitcoin::consensus::encode::serialize; use bitcoin::consensus::encode::serialize;
@ -124,6 +124,62 @@ impl<K, A> WalletUpdate<K, A> {
} }
} }
/// A structure that records the corresponding changes as result of applying an [`WalletUpdate`].
#[derive(Debug, Clone, PartialEq, serde::Serialize, serde::Deserialize)]
pub struct WalletChangeSet<K, A> {
/// Changes to the [`LocalChain`].
///
/// [`LocalChain`]: local_chain::LocalChain
pub chain: local_chain::ChangeSet,
/// ChangeSet to [`IndexedTxGraph`].
///
/// [`IndexedTxGraph`]: bdk_chain::indexed_tx_graph::IndexedTxGraph
#[serde(bound(
deserialize = "K: Ord + serde::Deserialize<'de>, A: Ord + serde::Deserialize<'de>",
serialize = "K: Ord + serde::Serialize, A: Ord + serde::Serialize",
))]
pub index_tx_graph: indexed_tx_graph::ChangeSet<A, keychain::ChangeSet<K>>,
}
impl<K, A> Default for WalletChangeSet<K, A> {
fn default() -> Self {
Self {
chain: Default::default(),
index_tx_graph: Default::default(),
}
}
}
impl<K: Ord, A: Anchor> Append for WalletChangeSet<K, A> {
fn append(&mut self, other: Self) {
Append::append(&mut self.chain, other.chain);
Append::append(&mut self.index_tx_graph, other.index_tx_graph);
}
fn is_empty(&self) -> bool {
self.chain.is_empty() && self.index_tx_graph.is_empty()
}
}
impl<K, A> From<local_chain::ChangeSet> for WalletChangeSet<K, A> {
fn from(chain: local_chain::ChangeSet) -> Self {
Self {
chain,
..Default::default()
}
}
}
impl<K, A> From<indexed_tx_graph::ChangeSet<A, keychain::ChangeSet<K>>> for WalletChangeSet<K, A> {
fn from(index_tx_graph: indexed_tx_graph::ChangeSet<A, keychain::ChangeSet<K>>) -> Self {
Self {
index_tx_graph,
..Default::default()
}
}
}
/// The update to a [`Wallet`] used in [`Wallet::apply_update`]. This is usually returned from blockchain data sources. /// The update to a [`Wallet`] used in [`Wallet::apply_update`]. This is usually returned from blockchain data sources.
pub type Update = WalletUpdate<KeychainKind, ConfirmationTimeAnchor>; pub type Update = WalletUpdate<KeychainKind, ConfirmationTimeAnchor>;
@ -277,7 +333,7 @@ impl<D> Wallet<D> {
let changeset = db.load_from_persistence().map_err(NewError::Persist)?; let changeset = db.load_from_persistence().map_err(NewError::Persist)?;
chain.apply_changeset(&changeset.chain); chain.apply_changeset(&changeset.chain);
indexed_graph.apply_changeset(changeset.indexed_tx_graph); indexed_graph.apply_changeset(changeset.index_tx_graph);
let persist = Persist::new(db); let persist = Persist::new(db);

View File

@ -10,7 +10,7 @@
//! //!
//! [`SpkTxOutIndex`]: crate::SpkTxOutIndex //! [`SpkTxOutIndex`]: crate::SpkTxOutIndex
use crate::{collections::BTreeMap, indexed_tx_graph, local_chain, Anchor, Append}; use crate::{collections::BTreeMap, Append};
#[cfg(feature = "miniscript")] #[cfg(feature = "miniscript")]
mod txout_index; mod txout_index;
@ -80,69 +80,6 @@ impl<K> AsRef<BTreeMap<K, u32>> for ChangeSet<K> {
} }
} }
/// A structure that records the corresponding changes as result of applying an [`WalletUpdate`].
#[derive(Debug, Clone, PartialEq)]
#[cfg_attr(
feature = "serde",
derive(serde::Deserialize, serde::Serialize),
serde(
crate = "serde_crate",
bound(
deserialize = "K: Ord + serde::Deserialize<'de>, A: Ord + serde::Deserialize<'de>",
serialize = "K: Ord + serde::Serialize, A: Ord + serde::Serialize",
)
)
)]
pub struct WalletChangeSet<K, A> {
/// Changes to the [`LocalChain`].
///
/// [`LocalChain`]: local_chain::LocalChain
pub chain: local_chain::ChangeSet,
/// ChangeSet to [`IndexedTxGraph`].
///
/// [`IndexedTxGraph`]: crate::indexed_tx_graph::IndexedTxGraph
pub indexed_tx_graph: indexed_tx_graph::ChangeSet<A, ChangeSet<K>>,
}
impl<K, A> Default for WalletChangeSet<K, A> {
fn default() -> Self {
Self {
chain: Default::default(),
indexed_tx_graph: Default::default(),
}
}
}
impl<K: Ord, A: Anchor> Append for WalletChangeSet<K, A> {
fn append(&mut self, other: Self) {
Append::append(&mut self.chain, other.chain);
Append::append(&mut self.indexed_tx_graph, other.indexed_tx_graph);
}
fn is_empty(&self) -> bool {
self.chain.is_empty() && self.indexed_tx_graph.is_empty()
}
}
impl<K, A> From<local_chain::ChangeSet> for WalletChangeSet<K, A> {
fn from(chain: local_chain::ChangeSet) -> Self {
Self {
chain,
..Default::default()
}
}
}
impl<K, A> From<indexed_tx_graph::ChangeSet<A, ChangeSet<K>>> for WalletChangeSet<K, A> {
fn from(indexed_tx_graph: indexed_tx_graph::ChangeSet<A, ChangeSet<K>>) -> Self {
Self {
indexed_tx_graph,
..Default::default()
}
}
}
/// Balance, differentiated into various categories. /// Balance, differentiated into various categories.
#[derive(Debug, PartialEq, Eq, Clone, Default)] #[derive(Debug, PartialEq, Eq, Clone, Default)]
#[cfg_attr( #[cfg_attr(

View File

@ -100,3 +100,11 @@ pub mod collections {
/// How many confirmations are needed f or a coinbase output to be spent. /// How many confirmations are needed f or a coinbase output to be spent.
pub const COINBASE_MATURITY: u32 = 100; pub const COINBASE_MATURITY: u32 = 100;
impl<A, IA> From<indexed_tx_graph::ChangeSet<A, IA>>
for (local_chain::ChangeSet, indexed_tx_graph::ChangeSet<A, IA>)
{
fn from(indexed_changeset: indexed_tx_graph::ChangeSet<A, IA>) -> Self {
(local_chain::ChangeSet::default(), indexed_changeset)
}
}

View File

@ -7,7 +7,7 @@ use std::{
use bdk_chain::{ use bdk_chain::{
bitcoin::{Address, Network, OutPoint, ScriptBuf, Txid}, bitcoin::{Address, Network, OutPoint, ScriptBuf, Txid},
indexed_tx_graph::{self, IndexedTxGraph}, indexed_tx_graph::{self, IndexedTxGraph},
keychain::WalletChangeSet, keychain,
local_chain::{self, LocalChain}, local_chain::{self, LocalChain},
Append, ConfirmationHeightAnchor, Append, ConfirmationHeightAnchor,
}; };
@ -60,7 +60,10 @@ pub struct ScanOptions {
pub batch_size: usize, pub batch_size: usize,
} }
type ChangeSet = WalletChangeSet<Keychain, ConfirmationHeightAnchor>; type ChangeSet = (
local_chain::ChangeSet,
indexed_tx_graph::ChangeSet<ConfirmationHeightAnchor, keychain::ChangeSet<Keychain>>,
);
fn main() -> anyhow::Result<()> { fn main() -> anyhow::Result<()> {
let (args, keymap, index, db, init_changeset) = let (args, keymap, index, db, init_changeset) =
@ -68,11 +71,11 @@ fn main() -> anyhow::Result<()> {
let graph = Mutex::new({ let graph = Mutex::new({
let mut graph = IndexedTxGraph::new(index); let mut graph = IndexedTxGraph::new(index);
graph.apply_changeset(init_changeset.indexed_tx_graph); graph.apply_changeset(init_changeset.1);
graph graph
}); });
let chain = Mutex::new(LocalChain::from_changeset(init_changeset.chain)); let chain = Mutex::new(LocalChain::from_changeset(init_changeset.0));
let electrum_url = match args.network { let electrum_url = match args.network {
Network::Bitcoin => "ssl://electrum.blockstream.info:50002", Network::Bitcoin => "ssl://electrum.blockstream.info:50002",
@ -293,10 +296,7 @@ fn main() -> anyhow::Result<()> {
changeset changeset
}; };
ChangeSet { (chain, indexed_tx_graph)
indexed_tx_graph,
chain,
}
}; };
let mut db = db.lock().unwrap(); let mut db = db.lock().unwrap();

View File

@ -6,9 +6,9 @@ use std::{
use bdk_chain::{ use bdk_chain::{
bitcoin::{Address, Network, OutPoint, ScriptBuf, Txid}, bitcoin::{Address, Network, OutPoint, ScriptBuf, Txid},
indexed_tx_graph::IndexedTxGraph, indexed_tx_graph::{self, IndexedTxGraph},
keychain::WalletChangeSet, keychain,
local_chain::{CheckPoint, LocalChain}, local_chain::{self, CheckPoint, LocalChain},
Append, ConfirmationTimeAnchor, Append, ConfirmationTimeAnchor,
}; };
@ -23,6 +23,11 @@ use example_cli::{
const DB_MAGIC: &[u8] = b"bdk_example_esplora"; const DB_MAGIC: &[u8] = b"bdk_example_esplora";
const DB_PATH: &str = ".bdk_esplora_example.db"; const DB_PATH: &str = ".bdk_esplora_example.db";
type ChangeSet = (
local_chain::ChangeSet,
indexed_tx_graph::ChangeSet<ConfirmationTimeAnchor, keychain::ChangeSet<Keychain>>,
);
#[derive(Subcommand, Debug, Clone)] #[derive(Subcommand, Debug, Clone)]
enum EsploraCommands { enum EsploraCommands {
/// Scans the addresses in the wallet using the esplora API. /// Scans the addresses in the wallet using the esplora API.
@ -60,22 +65,22 @@ pub struct ScanOptions {
} }
fn main() -> anyhow::Result<()> { fn main() -> anyhow::Result<()> {
let (args, keymap, index, db, init_changeset) = example_cli::init::< let (args, keymap, index, db, init_changeset) =
EsploraCommands, example_cli::init::<EsploraCommands, ChangeSet>(DB_MAGIC, DB_PATH)?;
WalletChangeSet<Keychain, ConfirmationTimeAnchor>,
>(DB_MAGIC, DB_PATH)?; let (init_chain_changeset, init_indexed_tx_graph_changeset) = init_changeset;
// Contruct `IndexedTxGraph` and `LocalChain` with our initial changeset. They are wrapped in // Contruct `IndexedTxGraph` and `LocalChain` with our initial changeset. They are wrapped in
// `Mutex` to display how they can be used in a multithreaded context. Technically the mutexes // `Mutex` to display how they can be used in a multithreaded context. Technically the mutexes
// aren't strictly needed here. // aren't strictly needed here.
let graph = Mutex::new({ let graph = Mutex::new({
let mut graph = IndexedTxGraph::new(index); let mut graph = IndexedTxGraph::new(index);
graph.apply_changeset(init_changeset.indexed_tx_graph); graph.apply_changeset(init_indexed_tx_graph_changeset);
graph graph
}); });
let chain = Mutex::new({ let chain = Mutex::new({
let mut chain = LocalChain::default(); let mut chain = LocalChain::default();
chain.apply_changeset(&init_changeset.chain); chain.apply_changeset(&init_chain_changeset);
chain chain
}); });
@ -307,18 +312,17 @@ fn main() -> anyhow::Result<()> {
println!("missing block heights: {:?}", missing_block_heights); println!("missing block heights: {:?}", missing_block_heights);
// Here, we actually fetch the missing blocks and create a `local_chain::Update`. // Here, we actually fetch the missing blocks and create a `local_chain::Update`.
let chain_update = client let chain_changeset = {
.update_local_chain(tip, missing_block_heights) let chain_update = client
.context("scanning for blocks")?; .update_local_chain(tip, missing_block_heights)
.context("scanning for blocks")?;
println!("new tip: {}", chain_update.tip.height()); println!("new tip: {}", chain_update.tip.height());
chain.lock().unwrap().apply_update(chain_update)?
};
// We persist the changes // We persist the changes
let mut db = db.lock().unwrap(); let mut db = db.lock().unwrap();
db.stage(WalletChangeSet { db.stage((chain_changeset, indexed_tx_graph_changeset));
chain: chain.lock().unwrap().apply_update(chain_update)?,
indexed_tx_graph: indexed_tx_graph_changeset,
});
db.commit()?; db.commit()?;
Ok(()) Ok(())
} }