Introduce keychain::LocalChangeSet
				
					
				
			This corresponds to `keychain::KeychainChangeSet` but for the redesigned structures with `LocalChain`. This structure is now used in `Wallet` as well as the examples.
This commit is contained in:
		
							parent
							
								
									a78967e51b
								
							
						
					
					
						commit
						50425e979b
					
				| @ -22,11 +22,11 @@ use alloc::{ | |||||||
| pub use bdk_chain::keychain::Balance; | pub use bdk_chain::keychain::Balance; | ||||||
| use bdk_chain::{ | use bdk_chain::{ | ||||||
|     indexed_tx_graph::{IndexedAdditions, IndexedTxGraph}, |     indexed_tx_graph::{IndexedAdditions, IndexedTxGraph}, | ||||||
|     keychain::{DerivationAdditions, KeychainTxOutIndex, LocalUpdate}, |     keychain::{KeychainTxOutIndex, LocalChangeSet, LocalUpdate}, | ||||||
|     local_chain::{self, LocalChain, UpdateNotConnectedError}, |     local_chain::{self, LocalChain, UpdateNotConnectedError}, | ||||||
|     tx_graph::{CanonicalTx, TxGraph}, |     tx_graph::{CanonicalTx, TxGraph}, | ||||||
|     Anchor, Append, BlockId, ConfirmationTime, ConfirmationTimeAnchor, FullTxOut, ObservedAs, |     Append, BlockId, ConfirmationTime, ConfirmationTimeAnchor, FullTxOut, ObservedAs, Persist, | ||||||
|     Persist, PersistBackend, |     PersistBackend, | ||||||
| }; | }; | ||||||
| use bitcoin::consensus::encode::serialize; | use bitcoin::consensus::encode::serialize; | ||||||
| use bitcoin::secp256k1::Secp256k1; | use bitcoin::secp256k1::Secp256k1; | ||||||
| @ -96,67 +96,8 @@ pub struct Wallet<D = ()> { | |||||||
| /// 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 = LocalUpdate<KeychainKind, ConfirmationTimeAnchor>; | pub type Update = LocalUpdate<KeychainKind, ConfirmationTimeAnchor>; | ||||||
| 
 | 
 | ||||||
| /// The changeset produced internally by applying an update.
 | // /// The changeset produced internally by applying an update.
 | ||||||
| #[derive(Debug, PartialEq, serde::Deserialize, serde::Serialize)] | pub(crate) type ChangeSet = LocalChangeSet<KeychainKind, ConfirmationTimeAnchor>; | ||||||
| #[serde(bound(
 |  | ||||||
|     deserialize = "A: Ord + serde::Deserialize<'de>, K: Ord + serde::Deserialize<'de>", |  | ||||||
|     serialize = "A: Ord + serde::Serialize, K: Ord + serde::Serialize" |  | ||||||
| ))] |  | ||||||
| pub struct ChangeSet<K = KeychainKind, A = ConfirmationTimeAnchor> { |  | ||||||
|     pub chain_changeset: local_chain::ChangeSet, |  | ||||||
|     pub indexed_additions: IndexedAdditions<A, DerivationAdditions<K>>, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl<K, A> Default for ChangeSet<K, A> { |  | ||||||
|     fn default() -> Self { |  | ||||||
|         Self { |  | ||||||
|             chain_changeset: Default::default(), |  | ||||||
|             indexed_additions: Default::default(), |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl<K: Ord, A: Anchor> Append for ChangeSet<K, A> { |  | ||||||
|     fn append(&mut self, other: Self) { |  | ||||||
|         Append::append(&mut self.chain_changeset, other.chain_changeset); |  | ||||||
|         Append::append(&mut self.indexed_additions, other.indexed_additions); |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     fn is_empty(&self) -> bool { |  | ||||||
|         self.chain_changeset.is_empty() && self.indexed_additions.is_empty() |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl<K, A> From<IndexedAdditions<A, DerivationAdditions<K>>> for ChangeSet<K, A> { |  | ||||||
|     fn from(indexed_additions: IndexedAdditions<A, DerivationAdditions<K>>) -> Self { |  | ||||||
|         Self { |  | ||||||
|             indexed_additions, |  | ||||||
|             ..Default::default() |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl<K, A> From<DerivationAdditions<K>> for ChangeSet<K, A> { |  | ||||||
|     fn from(index_additions: DerivationAdditions<K>) -> Self { |  | ||||||
|         Self { |  | ||||||
|             indexed_additions: IndexedAdditions { |  | ||||||
|                 index_additions, |  | ||||||
|                 ..Default::default() |  | ||||||
|             }, |  | ||||||
|             ..Default::default() |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl<K, A> From<local_chain::ChangeSet> for ChangeSet<K, A> { |  | ||||||
|     fn from(chain_changeset: local_chain::ChangeSet) -> Self { |  | ||||||
|         Self { |  | ||||||
|             chain_changeset, |  | ||||||
|             ..Default::default() |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| /// The address index selection strategy to use to derived an address from the wallet's external
 | /// The address index selection strategy to use to derived an address from the wallet's external
 | ||||||
| /// descriptor. See [`Wallet::get_address`]. If you're unsure which one to use use `WalletIndex::New`.
 | /// descriptor. See [`Wallet::get_address`]. If you're unsure which one to use use `WalletIndex::New`.
 | ||||||
| #[derive(Debug)] | #[derive(Debug)] | ||||||
| @ -356,10 +297,11 @@ impl<D> Wallet<D> { | |||||||
|         let txout_index = &mut self.indexed_graph.index; |         let txout_index = &mut self.indexed_graph.index; | ||||||
|         let (index, spk) = match address_index { |         let (index, spk) = match address_index { | ||||||
|             AddressIndex::New => { |             AddressIndex::New => { | ||||||
|                 let ((index, spk), changeset) = txout_index.reveal_next_spk(&keychain); |                 let ((index, spk), index_additions) = txout_index.reveal_next_spk(&keychain); | ||||||
|                 let spk = spk.clone(); |                 let spk = spk.clone(); | ||||||
| 
 | 
 | ||||||
|                 self.persist.stage(changeset.into()); |                 self.persist | ||||||
|  |                     .stage(ChangeSet::from(IndexedAdditions::from(index_additions))); | ||||||
|                 self.persist.commit().expect("TODO"); |                 self.persist.commit().expect("TODO"); | ||||||
|                 (index, spk) |                 (index, spk) | ||||||
|             } |             } | ||||||
| @ -931,11 +873,12 @@ impl<D> Wallet<D> { | |||||||
|             Some(ref drain_recipient) => drain_recipient.clone(), |             Some(ref drain_recipient) => drain_recipient.clone(), | ||||||
|             None => { |             None => { | ||||||
|                 let change_keychain = self.map_keychain(KeychainKind::Internal); |                 let change_keychain = self.map_keychain(KeychainKind::Internal); | ||||||
|                 let ((index, spk), changeset) = |                 let ((index, spk), index_additions) = | ||||||
|                     self.indexed_graph.index.next_unused_spk(&change_keychain); |                     self.indexed_graph.index.next_unused_spk(&change_keychain); | ||||||
|                 let spk = spk.clone(); |                 let spk = spk.clone(); | ||||||
|                 self.indexed_graph.index.mark_used(&change_keychain, index); |                 self.indexed_graph.index.mark_used(&change_keychain, index); | ||||||
|                 self.persist.stage(changeset.into()); |                 self.persist | ||||||
|  |                     .stage(ChangeSet::from(IndexedAdditions::from(index_additions))); | ||||||
|                 self.persist.commit().expect("TODO"); |                 self.persist.commit().expect("TODO"); | ||||||
|                 spk |                 spk | ||||||
|             } |             } | ||||||
| @ -1751,11 +1694,11 @@ impl<D> Wallet<D> { | |||||||
|         D: PersistBackend<ChangeSet>, |         D: PersistBackend<ChangeSet>, | ||||||
|     { |     { | ||||||
|         let mut changeset: ChangeSet = self.chain.apply_update(update.chain)?.into(); |         let mut changeset: ChangeSet = self.chain.apply_update(update.chain)?.into(); | ||||||
|         let (_, derivation_additions) = self |         let (_, index_additions) = self | ||||||
|             .indexed_graph |             .indexed_graph | ||||||
|             .index |             .index | ||||||
|             .reveal_to_target_multi(&update.keychain); |             .reveal_to_target_multi(&update.keychain); | ||||||
|         changeset.append(derivation_additions.into()); |         changeset.append(ChangeSet::from(IndexedAdditions::from(index_additions))); | ||||||
|         changeset.append(self.indexed_graph.apply_update(update.graph).into()); |         changeset.append(self.indexed_graph.apply_update(update.graph).into()); | ||||||
| 
 | 
 | ||||||
|         let changed = !changeset.is_empty(); |         let changed = !changeset.is_empty(); | ||||||
|  | |||||||
| @ -2,6 +2,7 @@ use alloc::vec::Vec; | |||||||
| use bitcoin::{OutPoint, Transaction, TxOut}; | use bitcoin::{OutPoint, Transaction, TxOut}; | ||||||
| 
 | 
 | ||||||
| use crate::{ | use crate::{ | ||||||
|  |     keychain::DerivationAdditions, | ||||||
|     tx_graph::{Additions, TxGraph}, |     tx_graph::{Additions, TxGraph}, | ||||||
|     Anchor, Append, |     Anchor, Append, | ||||||
| }; | }; | ||||||
| @ -212,6 +213,15 @@ impl<A, IA: Default> From<Additions<A>> for IndexedAdditions<A, IA> { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | impl<A, K> From<DerivationAdditions<K>> for IndexedAdditions<A, DerivationAdditions<K>> { | ||||||
|  |     fn from(index_additions: DerivationAdditions<K>) -> Self { | ||||||
|  |         Self { | ||||||
|  |             graph_additions: Default::default(), | ||||||
|  |             index_additions, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| /// Represents a structure that can index transaction data.
 | /// Represents a structure that can index transaction data.
 | ||||||
| pub trait Indexer { | pub trait Indexer { | ||||||
|     /// The resultant "additions" when new transaction data is indexed.
 |     /// The resultant "additions" when new transaction data is indexed.
 | ||||||
|  | |||||||
| @ -18,10 +18,11 @@ | |||||||
| use crate::{ | use crate::{ | ||||||
|     chain_graph::{self, ChainGraph}, |     chain_graph::{self, ChainGraph}, | ||||||
|     collections::BTreeMap, |     collections::BTreeMap, | ||||||
|     local_chain::LocalChain, |     indexed_tx_graph::IndexedAdditions, | ||||||
|  |     local_chain::{self, LocalChain}, | ||||||
|     sparse_chain::ChainPosition, |     sparse_chain::ChainPosition, | ||||||
|     tx_graph::TxGraph, |     tx_graph::TxGraph, | ||||||
|     Append, ForEachTxOut, |     Anchor, Append, ForEachTxOut, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| #[cfg(feature = "miniscript")] | #[cfg(feature = "miniscript")] | ||||||
| @ -125,6 +126,67 @@ impl<K, A> Default for LocalUpdate<K, A> { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | /// A structure that records the corresponding changes as result of applying an [`LocalUpdate`].
 | ||||||
|  | #[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 LocalChangeSet<K, A> { | ||||||
|  |     /// Changes to the [`LocalChain`].
 | ||||||
|  |     pub chain_changeset: local_chain::ChangeSet, | ||||||
|  | 
 | ||||||
|  |     /// Additions to [`IndexedTxGraph`].
 | ||||||
|  |     ///
 | ||||||
|  |     /// [`IndexedTxGraph`]: crate::indexed_tx_graph::IndexedTxGraph
 | ||||||
|  |     pub indexed_additions: IndexedAdditions<A, DerivationAdditions<K>>, | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<K, A> Default for LocalChangeSet<K, A> { | ||||||
|  |     fn default() -> Self { | ||||||
|  |         Self { | ||||||
|  |             chain_changeset: Default::default(), | ||||||
|  |             indexed_additions: Default::default(), | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<K: Ord, A: Anchor> Append for LocalChangeSet<K, A> { | ||||||
|  |     fn append(&mut self, other: Self) { | ||||||
|  |         Append::append(&mut self.chain_changeset, other.chain_changeset); | ||||||
|  |         Append::append(&mut self.indexed_additions, other.indexed_additions); | ||||||
|  |     } | ||||||
|  | 
 | ||||||
|  |     fn is_empty(&self) -> bool { | ||||||
|  |         self.chain_changeset.is_empty() && self.indexed_additions.is_empty() | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<K, A> From<local_chain::ChangeSet> for LocalChangeSet<K, A> { | ||||||
|  |     fn from(chain_changeset: local_chain::ChangeSet) -> Self { | ||||||
|  |         Self { | ||||||
|  |             chain_changeset, | ||||||
|  |             ..Default::default() | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | impl<K, A> From<IndexedAdditions<A, DerivationAdditions<K>>> for LocalChangeSet<K, A> { | ||||||
|  |     fn from(indexed_additions: IndexedAdditions<A, DerivationAdditions<K>>) -> Self { | ||||||
|  |         Self { | ||||||
|  |             indexed_additions, | ||||||
|  |             ..Default::default() | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
| #[derive(Clone, Debug, PartialEq)] | #[derive(Clone, Debug, PartialEq)] | ||||||
| /// An update that includes the last active indexes of each keychain.
 | /// An update that includes the last active indexes of each keychain.
 | ||||||
| pub struct KeychainScan<K, P> { | pub struct KeychainScan<K, P> { | ||||||
|  | |||||||
| @ -26,42 +26,13 @@ pub use clap; | |||||||
| use clap::{Parser, Subcommand}; | use clap::{Parser, Subcommand}; | ||||||
| 
 | 
 | ||||||
| pub type KeychainTxGraph<A> = IndexedTxGraph<A, KeychainTxOutIndex<Keychain>>; | pub type KeychainTxGraph<A> = IndexedTxGraph<A, KeychainTxOutIndex<Keychain>>; | ||||||
| pub type Database<'m, A, X> = Persist<Store<'m, ChangeSet<A, X>>, ChangeSet<A, X>>; | pub type KeychainAdditions<A> = IndexedAdditions<A, DerivationAdditions<Keychain>>; | ||||||
| 
 | pub type Database<'m, C> = Persist<Store<'m, C>, C>; | ||||||
| #[derive(Debug, Clone, PartialEq, serde::Deserialize, serde::Serialize)] |  | ||||||
| #[serde(bound(
 |  | ||||||
|     deserialize = "A: Ord + serde::Deserialize<'de>, X: serde::Deserialize<'de>", |  | ||||||
|     serialize = "A: Ord + serde::Serialize, X: serde::Serialize", |  | ||||||
| ))] |  | ||||||
| pub struct ChangeSet<A, X> { |  | ||||||
|     pub indexed_additions: IndexedAdditions<A, DerivationAdditions<Keychain>>, |  | ||||||
|     pub extension: X, |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl<A, X: Default> Default for ChangeSet<A, X> { |  | ||||||
|     fn default() -> Self { |  | ||||||
|         Self { |  | ||||||
|             indexed_additions: Default::default(), |  | ||||||
|             extension: Default::default(), |  | ||||||
|         } |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 |  | ||||||
| impl<A: Anchor, X: Append> Append for ChangeSet<A, X> { |  | ||||||
|     fn append(&mut self, other: Self) { |  | ||||||
|         Append::append(&mut self.indexed_additions, other.indexed_additions); |  | ||||||
|         Append::append(&mut self.extension, other.extension) |  | ||||||
|     } |  | ||||||
| 
 |  | ||||||
|     fn is_empty(&self) -> bool { |  | ||||||
|         self.indexed_additions.is_empty() && self.extension.is_empty() |  | ||||||
|     } |  | ||||||
| } |  | ||||||
| 
 | 
 | ||||||
| #[derive(Parser)] | #[derive(Parser)] | ||||||
| #[clap(author, version, about, long_about = None)] | #[clap(author, version, about, long_about = None)] | ||||||
| #[clap(propagate_version = true)] | #[clap(propagate_version = true)] | ||||||
| pub struct Args<C: clap::Subcommand> { | pub struct Args<S: clap::Subcommand> { | ||||||
|     #[clap(env = "DESCRIPTOR")] |     #[clap(env = "DESCRIPTOR")] | ||||||
|     pub descriptor: String, |     pub descriptor: String, | ||||||
|     #[clap(env = "CHANGE_DESCRIPTOR")] |     #[clap(env = "CHANGE_DESCRIPTOR")] | ||||||
| @ -77,14 +48,14 @@ pub struct Args<C: clap::Subcommand> { | |||||||
|     pub cp_limit: usize, |     pub cp_limit: usize, | ||||||
| 
 | 
 | ||||||
|     #[clap(subcommand)] |     #[clap(subcommand)] | ||||||
|     pub command: Commands<C>, |     pub command: Commands<S>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[allow(clippy::almost_swapped)] | #[allow(clippy::almost_swapped)] | ||||||
| #[derive(Subcommand, Debug, Clone)] | #[derive(Subcommand, Debug, Clone)] | ||||||
| pub enum Commands<C: clap::Subcommand> { | pub enum Commands<S: clap::Subcommand> { | ||||||
|     #[clap(flatten)] |     #[clap(flatten)] | ||||||
|     ChainSpecific(C), |     ChainSpecific(S), | ||||||
|     /// Address generation and inspection.
 |     /// Address generation and inspection.
 | ||||||
|     Address { |     Address { | ||||||
|         #[clap(subcommand)] |         #[clap(subcommand)] | ||||||
| @ -210,14 +181,14 @@ impl core::fmt::Display for Keychain { | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn run_address_cmd<A, X>( | pub fn run_address_cmd<A, C>( | ||||||
|     graph: &mut KeychainTxGraph<A>, |     graph: &mut KeychainTxGraph<A>, | ||||||
|     db: &Mutex<Database<'_, A, X>>, |     db: &Mutex<Database<C>>, | ||||||
|     network: Network, |     network: Network, | ||||||
|     cmd: AddressCmd, |     cmd: AddressCmd, | ||||||
| ) -> anyhow::Result<()> | ) -> anyhow::Result<()> | ||||||
| where | where | ||||||
|     ChangeSet<A, X>: Default + Append + DeserializeOwned + Serialize, |     C: Default + Append + DeserializeOwned + Serialize + From<KeychainAdditions<A>>, | ||||||
| { | { | ||||||
|     let index = &mut graph.index; |     let index = &mut graph.index; | ||||||
| 
 | 
 | ||||||
| @ -231,13 +202,7 @@ where | |||||||
| 
 | 
 | ||||||
|             let ((spk_i, spk), index_additions) = spk_chooser(index, &Keychain::External); |             let ((spk_i, spk), index_additions) = spk_chooser(index, &Keychain::External); | ||||||
|             let db = &mut *db.lock().unwrap(); |             let db = &mut *db.lock().unwrap(); | ||||||
|             db.stage(ChangeSet { |             db.stage(C::from(KeychainAdditions::from(index_additions))); | ||||||
|                 indexed_additions: IndexedAdditions { |  | ||||||
|                     index_additions, |  | ||||||
|                     ..Default::default() |  | ||||||
|                 }, |  | ||||||
|                 ..Default::default() |  | ||||||
|             }); |  | ||||||
|             db.commit()?; |             db.commit()?; | ||||||
|             let addr = Address::from_script(spk, network).context("failed to derive address")?; |             let addr = Address::from_script(spk, network).context("failed to derive address")?; | ||||||
|             println!("[address @ {}] {}", spk_i, addr); |             println!("[address @ {}] {}", spk_i, addr); | ||||||
| @ -351,9 +316,9 @@ where | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[allow(clippy::too_many_arguments)] | #[allow(clippy::too_many_arguments)] | ||||||
| pub fn run_send_cmd<A: Anchor, O: ChainOracle, X>( | pub fn run_send_cmd<A: Anchor, O: ChainOracle, C>( | ||||||
|     graph: &Mutex<KeychainTxGraph<A>>, |     graph: &Mutex<KeychainTxGraph<A>>, | ||||||
|     db: &Mutex<Database<'_, A, X>>, |     db: &Mutex<Database<'_, C>>, | ||||||
|     chain: &O, |     chain: &O, | ||||||
|     keymap: &HashMap<DescriptorPublicKey, DescriptorSecretKey>, |     keymap: &HashMap<DescriptorPublicKey, DescriptorSecretKey>, | ||||||
|     cs_algorithm: CoinSelectionAlgo, |     cs_algorithm: CoinSelectionAlgo, | ||||||
| @ -363,7 +328,7 @@ pub fn run_send_cmd<A: Anchor, O: ChainOracle, X>( | |||||||
| ) -> anyhow::Result<()> | ) -> anyhow::Result<()> | ||||||
| where | where | ||||||
|     O::Error: std::error::Error + Send + Sync + 'static, |     O::Error: std::error::Error + Send + Sync + 'static, | ||||||
|     ChangeSet<A, X>: Default + Append + DeserializeOwned + Serialize, |     C: Default + Append + DeserializeOwned + Serialize + From<KeychainAdditions<A>>, | ||||||
| { | { | ||||||
|     let (transaction, change_index) = { |     let (transaction, change_index) = { | ||||||
|         let graph = &mut *graph.lock().unwrap(); |         let graph = &mut *graph.lock().unwrap(); | ||||||
| @ -374,13 +339,9 @@ where | |||||||
|             // We must first persist to disk the fact that we've got a new address from the
 |             // We must first persist to disk the fact that we've got a new address from the
 | ||||||
|             // change keychain so future scans will find the tx we're about to broadcast.
 |             // change keychain so future scans will find the tx we're about to broadcast.
 | ||||||
|             // If we're unable to persist this, then we don't want to broadcast.
 |             // If we're unable to persist this, then we don't want to broadcast.
 | ||||||
|             db.lock().unwrap().stage(ChangeSet { |             db.lock() | ||||||
|                 indexed_additions: IndexedAdditions { |                 .unwrap() | ||||||
|                     index_additions, |                 .stage(C::from(KeychainAdditions::from(index_additions))); | ||||||
|                     ..Default::default() |  | ||||||
|                 }, |  | ||||||
|                 ..Default::default() |  | ||||||
|             }); |  | ||||||
| 
 | 
 | ||||||
|             // We don't want other callers/threads to use this address while we're using it
 |             // We don't want other callers/threads to use this address while we're using it
 | ||||||
|             // but we also don't want to scan the tx we just created because it's not
 |             // but we also don't want to scan the tx we just created because it's not
 | ||||||
| @ -396,15 +357,12 @@ where | |||||||
|         Ok(_) => { |         Ok(_) => { | ||||||
|             println!("Broadcasted Tx : {}", transaction.txid()); |             println!("Broadcasted Tx : {}", transaction.txid()); | ||||||
| 
 | 
 | ||||||
|             let indexed_additions = graph.lock().unwrap().insert_tx(&transaction, None, None); |             let keychain_additions = graph.lock().unwrap().insert_tx(&transaction, None, None); | ||||||
| 
 | 
 | ||||||
|             // We know the tx is at least unconfirmed now. Note if persisting here fails,
 |             // We know the tx is at least unconfirmed now. Note if persisting here fails,
 | ||||||
|             // it's not a big deal since we can always find it again form
 |             // it's not a big deal since we can always find it again form
 | ||||||
|             // blockchain.
 |             // blockchain.
 | ||||||
|             db.lock().unwrap().stage(ChangeSet { |             db.lock().unwrap().stage(C::from(keychain_additions)); | ||||||
|                 indexed_additions, |  | ||||||
|                 ..Default::default() |  | ||||||
|             }); |  | ||||||
|             Ok(()) |             Ok(()) | ||||||
|         } |         } | ||||||
|         Err(e) => { |         Err(e) => { | ||||||
| @ -659,18 +617,18 @@ pub fn planned_utxos<A: Anchor, O: ChainOracle, K: Clone + bdk_tmp_plan::CanDeri | |||||||
|         .collect() |         .collect() | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn handle_commands<C: clap::Subcommand, A: Anchor, O: ChainOracle, X>( | pub fn handle_commands<S: clap::Subcommand, A: Anchor, O: ChainOracle, C>( | ||||||
|     graph: &Mutex<KeychainTxGraph<A>>, |     graph: &Mutex<KeychainTxGraph<A>>, | ||||||
|     db: &Mutex<Database<A, X>>, |     db: &Mutex<Database<C>>, | ||||||
|     chain: &Mutex<O>, |     chain: &Mutex<O>, | ||||||
|     keymap: &HashMap<DescriptorPublicKey, DescriptorSecretKey>, |     keymap: &HashMap<DescriptorPublicKey, DescriptorSecretKey>, | ||||||
|     network: Network, |     network: Network, | ||||||
|     broadcast: impl FnOnce(&Transaction) -> anyhow::Result<()>, |     broadcast: impl FnOnce(&Transaction) -> anyhow::Result<()>, | ||||||
|     cmd: Commands<C>, |     cmd: Commands<S>, | ||||||
| ) -> anyhow::Result<()> | ) -> anyhow::Result<()> | ||||||
| where | where | ||||||
|     O::Error: std::error::Error + Send + Sync + 'static, |     O::Error: std::error::Error + Send + Sync + 'static, | ||||||
|     ChangeSet<A, X>: Default + Append + DeserializeOwned + Serialize, |     C: Default + Append + DeserializeOwned + Serialize + From<KeychainAdditions<A>>, | ||||||
| { | { | ||||||
|     match cmd { |     match cmd { | ||||||
|         Commands::ChainSpecific(_) => unreachable!("example code should handle this!"), |         Commands::ChainSpecific(_) => unreachable!("example code should handle this!"), | ||||||
| @ -708,9 +666,9 @@ where | |||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| pub fn prepare_index<C: clap::Subcommand, SC: secp256k1::Signing>( | pub fn prepare_index<S: clap::Subcommand, CTX: secp256k1::Signing>( | ||||||
|     args: &Args<C>, |     args: &Args<S>, | ||||||
|     secp: &Secp256k1<SC>, |     secp: &Secp256k1<CTX>, | ||||||
| ) -> anyhow::Result<(KeychainTxOutIndex<Keychain>, KeyMap)> { | ) -> anyhow::Result<(KeychainTxOutIndex<Keychain>, KeyMap)> { | ||||||
|     let mut index = KeychainTxOutIndex::<Keychain>::default(); |     let mut index = KeychainTxOutIndex::<Keychain>::default(); | ||||||
| 
 | 
 | ||||||
| @ -732,18 +690,18 @@ pub fn prepare_index<C: clap::Subcommand, SC: secp256k1::Signing>( | |||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[allow(clippy::type_complexity)] | #[allow(clippy::type_complexity)] | ||||||
| pub fn init<'m, S: clap::Subcommand, A: Anchor, X>( | pub fn init<'m, S: clap::Subcommand, C>( | ||||||
|     db_magic: &'m [u8], |     db_magic: &'m [u8], | ||||||
|     db_default_path: &str, |     db_default_path: &str, | ||||||
| ) -> anyhow::Result<( | ) -> anyhow::Result<( | ||||||
|     Args<S>, |     Args<S>, | ||||||
|     KeyMap, |     KeyMap, | ||||||
|     Mutex<KeychainTxGraph<A>>, |     KeychainTxOutIndex<Keychain>, | ||||||
|     Mutex<Database<'m, A, X>>, |     Mutex<Database<'m, C>>, | ||||||
|     X, |     C, | ||||||
| )> | )> | ||||||
| where | where | ||||||
|     ChangeSet<A, X>: Default + Append + Serialize + DeserializeOwned, |     C: Default + Append + Serialize + DeserializeOwned, | ||||||
| { | { | ||||||
|     if std::env::var("BDK_DB_PATH").is_err() { |     if std::env::var("BDK_DB_PATH").is_err() { | ||||||
|         std::env::set_var("BDK_DB_PATH", db_default_path); |         std::env::set_var("BDK_DB_PATH", db_default_path); | ||||||
| @ -752,25 +710,19 @@ where | |||||||
|     let secp = Secp256k1::default(); |     let secp = Secp256k1::default(); | ||||||
|     let (index, keymap) = prepare_index(&args, &secp)?; |     let (index, keymap) = prepare_index(&args, &secp)?; | ||||||
| 
 | 
 | ||||||
|     let mut indexed_graph = IndexedTxGraph::<A, KeychainTxOutIndex<Keychain>>::new(index); |     let mut db_backend = match Store::<'m, C>::new_from_path(db_magic, &args.db_path) { | ||||||
| 
 |  | ||||||
|     let mut db_backend = |  | ||||||
|         match Store::<'m, ChangeSet<A, X>>::new_from_path(db_magic, args.db_path.as_path()) { |  | ||||||
|         Ok(db_backend) => db_backend, |         Ok(db_backend) => db_backend, | ||||||
|  |         // we cannot return `err` directly as it has lifetime `'m`
 | ||||||
|         Err(err) => return Err(anyhow::anyhow!("failed to init db backend: {:?}", err)), |         Err(err) => return Err(anyhow::anyhow!("failed to init db backend: {:?}", err)), | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|     let ChangeSet { |     let init_changeset = db_backend.load_from_persistence()?; | ||||||
|         indexed_additions, |  | ||||||
|         extension, |  | ||||||
|     } = db_backend.load_from_persistence()?; |  | ||||||
|     indexed_graph.apply_additions(indexed_additions); |  | ||||||
| 
 | 
 | ||||||
|     Ok(( |     Ok(( | ||||||
|         args, |         args, | ||||||
|         keymap, |         keymap, | ||||||
|         Mutex::new(indexed_graph), |         index, | ||||||
|         Mutex::new(Database::new(db_backend)), |         Mutex::new(Database::new(db_backend)), | ||||||
|         extension, |         init_changeset, | ||||||
|     )) |     )) | ||||||
| } | } | ||||||
|  | |||||||
| @ -6,8 +6,9 @@ use std::{ | |||||||
| 
 | 
 | ||||||
| use bdk_chain::{ | use bdk_chain::{ | ||||||
|     bitcoin::{Address, BlockHash, Network, OutPoint, Txid}, |     bitcoin::{Address, BlockHash, Network, OutPoint, Txid}, | ||||||
|     indexed_tx_graph::IndexedAdditions, |     indexed_tx_graph::{IndexedAdditions, IndexedTxGraph}, | ||||||
|     local_chain::{self, LocalChain}, |     keychain::LocalChangeSet, | ||||||
|  |     local_chain::LocalChain, | ||||||
|     Append, ConfirmationHeightAnchor, |     Append, ConfirmationHeightAnchor, | ||||||
| }; | }; | ||||||
| use bdk_electrum::{ | use bdk_electrum::{ | ||||||
| @ -17,6 +18,7 @@ use bdk_electrum::{ | |||||||
| use example_cli::{ | use example_cli::{ | ||||||
|     anyhow::{self, Context}, |     anyhow::{self, Context}, | ||||||
|     clap::{self, Parser, Subcommand}, |     clap::{self, Parser, Subcommand}, | ||||||
|  |     Keychain, | ||||||
| }; | }; | ||||||
| 
 | 
 | ||||||
| const DB_MAGIC: &[u8] = b"bdk_example_electrum"; | const DB_MAGIC: &[u8] = b"bdk_example_electrum"; | ||||||
| @ -59,15 +61,21 @@ pub struct ScanOptions { | |||||||
|     pub batch_size: usize, |     pub batch_size: usize, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | type ChangeSet = LocalChangeSet<Keychain, ConfirmationHeightAnchor>; | ||||||
|  | 
 | ||||||
| fn main() -> anyhow::Result<()> { | fn main() -> anyhow::Result<()> { | ||||||
|     let (args, keymap, graph, db, chain_changeset) = |     let (args, keymap, index, db, init_changeset) = | ||||||
|         example_cli::init::<ElectrumCommands, ConfirmationHeightAnchor, local_chain::ChangeSet>( |         example_cli::init::<ElectrumCommands, ChangeSet>(DB_MAGIC, DB_PATH)?; | ||||||
|             DB_MAGIC, DB_PATH, | 
 | ||||||
|         )?; |     let graph = Mutex::new({ | ||||||
|  |         let mut graph = IndexedTxGraph::new(index); | ||||||
|  |         graph.apply_additions(init_changeset.indexed_additions); | ||||||
|  |         graph | ||||||
|  |     }); | ||||||
| 
 | 
 | ||||||
|     let chain = Mutex::new({ |     let chain = Mutex::new({ | ||||||
|         let mut chain = LocalChain::default(); |         let mut chain = LocalChain::default(); | ||||||
|         chain.apply_changeset(chain_changeset); |         chain.apply_changeset(init_changeset.chain_changeset); | ||||||
|         chain |         chain | ||||||
|     }); |     }); | ||||||
| 
 | 
 | ||||||
| @ -302,9 +310,9 @@ fn main() -> anyhow::Result<()> { | |||||||
|             additions |             additions | ||||||
|         }; |         }; | ||||||
| 
 | 
 | ||||||
|         example_cli::ChangeSet { |         ChangeSet { | ||||||
|             indexed_additions, |             indexed_additions, | ||||||
|             extension: chain_changeset, |             chain_changeset, | ||||||
|         } |         } | ||||||
|     }; |     }; | ||||||
| 
 | 
 | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user