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; | ||||
| use bdk_chain::{ | ||||
|     indexed_tx_graph::{IndexedAdditions, IndexedTxGraph}, | ||||
|     keychain::{DerivationAdditions, KeychainTxOutIndex, LocalUpdate}, | ||||
|     keychain::{KeychainTxOutIndex, LocalChangeSet, LocalUpdate}, | ||||
|     local_chain::{self, LocalChain, UpdateNotConnectedError}, | ||||
|     tx_graph::{CanonicalTx, TxGraph}, | ||||
|     Anchor, Append, BlockId, ConfirmationTime, ConfirmationTimeAnchor, FullTxOut, ObservedAs, | ||||
|     Persist, PersistBackend, | ||||
|     Append, BlockId, ConfirmationTime, ConfirmationTimeAnchor, FullTxOut, ObservedAs, Persist, | ||||
|     PersistBackend, | ||||
| }; | ||||
| use bitcoin::consensus::encode::serialize; | ||||
| 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.
 | ||||
| pub type Update = LocalUpdate<KeychainKind, ConfirmationTimeAnchor>; | ||||
| 
 | ||||
| /// The changeset produced internally by applying an update.
 | ||||
| #[derive(Debug, PartialEq, serde::Deserialize, serde::Serialize)] | ||||
| #[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 changeset produced internally by applying an update.
 | ||||
| pub(crate) type ChangeSet = LocalChangeSet<KeychainKind, ConfirmationTimeAnchor>; | ||||
| /// 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`.
 | ||||
| #[derive(Debug)] | ||||
| @ -356,10 +297,11 @@ impl<D> Wallet<D> { | ||||
|         let txout_index = &mut self.indexed_graph.index; | ||||
|         let (index, spk) = match address_index { | ||||
|             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(); | ||||
| 
 | ||||
|                 self.persist.stage(changeset.into()); | ||||
|                 self.persist | ||||
|                     .stage(ChangeSet::from(IndexedAdditions::from(index_additions))); | ||||
|                 self.persist.commit().expect("TODO"); | ||||
|                 (index, spk) | ||||
|             } | ||||
| @ -931,11 +873,12 @@ impl<D> Wallet<D> { | ||||
|             Some(ref drain_recipient) => drain_recipient.clone(), | ||||
|             None => { | ||||
|                 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); | ||||
|                 let spk = spk.clone(); | ||||
|                 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"); | ||||
|                 spk | ||||
|             } | ||||
| @ -1751,11 +1694,11 @@ impl<D> Wallet<D> { | ||||
|         D: PersistBackend<ChangeSet>, | ||||
|     { | ||||
|         let mut changeset: ChangeSet = self.chain.apply_update(update.chain)?.into(); | ||||
|         let (_, derivation_additions) = self | ||||
|         let (_, index_additions) = self | ||||
|             .indexed_graph | ||||
|             .index | ||||
|             .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()); | ||||
| 
 | ||||
|         let changed = !changeset.is_empty(); | ||||
|  | ||||
| @ -2,6 +2,7 @@ use alloc::vec::Vec; | ||||
| use bitcoin::{OutPoint, Transaction, TxOut}; | ||||
| 
 | ||||
| use crate::{ | ||||
|     keychain::DerivationAdditions, | ||||
|     tx_graph::{Additions, TxGraph}, | ||||
|     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.
 | ||||
| pub trait Indexer { | ||||
|     /// The resultant "additions" when new transaction data is indexed.
 | ||||
|  | ||||
| @ -18,10 +18,11 @@ | ||||
| use crate::{ | ||||
|     chain_graph::{self, ChainGraph}, | ||||
|     collections::BTreeMap, | ||||
|     local_chain::LocalChain, | ||||
|     indexed_tx_graph::IndexedAdditions, | ||||
|     local_chain::{self, LocalChain}, | ||||
|     sparse_chain::ChainPosition, | ||||
|     tx_graph::TxGraph, | ||||
|     Append, ForEachTxOut, | ||||
|     Anchor, Append, ForEachTxOut, | ||||
| }; | ||||
| 
 | ||||
| #[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)] | ||||
| /// An update that includes the last active indexes of each keychain.
 | ||||
| pub struct KeychainScan<K, P> { | ||||
|  | ||||
| @ -26,42 +26,13 @@ pub use clap; | ||||
| use clap::{Parser, Subcommand}; | ||||
| 
 | ||||
| pub type KeychainTxGraph<A> = IndexedTxGraph<A, KeychainTxOutIndex<Keychain>>; | ||||
| pub type Database<'m, A, X> = Persist<Store<'m, ChangeSet<A, X>>, ChangeSet<A, X>>; | ||||
| 
 | ||||
| #[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() | ||||
|     } | ||||
| } | ||||
| pub type KeychainAdditions<A> = IndexedAdditions<A, DerivationAdditions<Keychain>>; | ||||
| pub type Database<'m, C> = Persist<Store<'m, C>, C>; | ||||
| 
 | ||||
| #[derive(Parser)] | ||||
| #[clap(author, version, about, long_about = None)] | ||||
| #[clap(propagate_version = true)] | ||||
| pub struct Args<C: clap::Subcommand> { | ||||
| pub struct Args<S: clap::Subcommand> { | ||||
|     #[clap(env = "DESCRIPTOR")] | ||||
|     pub descriptor: String, | ||||
|     #[clap(env = "CHANGE_DESCRIPTOR")] | ||||
| @ -77,14 +48,14 @@ pub struct Args<C: clap::Subcommand> { | ||||
|     pub cp_limit: usize, | ||||
| 
 | ||||
|     #[clap(subcommand)] | ||||
|     pub command: Commands<C>, | ||||
|     pub command: Commands<S>, | ||||
| } | ||||
| 
 | ||||
| #[allow(clippy::almost_swapped)] | ||||
| #[derive(Subcommand, Debug, Clone)] | ||||
| pub enum Commands<C: clap::Subcommand> { | ||||
| pub enum Commands<S: clap::Subcommand> { | ||||
|     #[clap(flatten)] | ||||
|     ChainSpecific(C), | ||||
|     ChainSpecific(S), | ||||
|     /// Address generation and inspection.
 | ||||
|     Address { | ||||
|         #[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>, | ||||
|     db: &Mutex<Database<'_, A, X>>, | ||||
|     db: &Mutex<Database<C>>, | ||||
|     network: Network, | ||||
|     cmd: AddressCmd, | ||||
| ) -> anyhow::Result<()> | ||||
| where | ||||
|     ChangeSet<A, X>: Default + Append + DeserializeOwned + Serialize, | ||||
|     C: Default + Append + DeserializeOwned + Serialize + From<KeychainAdditions<A>>, | ||||
| { | ||||
|     let index = &mut graph.index; | ||||
| 
 | ||||
| @ -231,13 +202,7 @@ where | ||||
| 
 | ||||
|             let ((spk_i, spk), index_additions) = spk_chooser(index, &Keychain::External); | ||||
|             let db = &mut *db.lock().unwrap(); | ||||
|             db.stage(ChangeSet { | ||||
|                 indexed_additions: IndexedAdditions { | ||||
|                     index_additions, | ||||
|                     ..Default::default() | ||||
|                 }, | ||||
|                 ..Default::default() | ||||
|             }); | ||||
|             db.stage(C::from(KeychainAdditions::from(index_additions))); | ||||
|             db.commit()?; | ||||
|             let addr = Address::from_script(spk, network).context("failed to derive address")?; | ||||
|             println!("[address @ {}] {}", spk_i, addr); | ||||
| @ -351,9 +316,9 @@ where | ||||
| } | ||||
| 
 | ||||
| #[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>>, | ||||
|     db: &Mutex<Database<'_, A, X>>, | ||||
|     db: &Mutex<Database<'_, C>>, | ||||
|     chain: &O, | ||||
|     keymap: &HashMap<DescriptorPublicKey, DescriptorSecretKey>, | ||||
|     cs_algorithm: CoinSelectionAlgo, | ||||
| @ -363,7 +328,7 @@ pub fn run_send_cmd<A: Anchor, O: ChainOracle, X>( | ||||
| ) -> anyhow::Result<()> | ||||
| where | ||||
|     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 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
 | ||||
|             // 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.
 | ||||
|             db.lock().unwrap().stage(ChangeSet { | ||||
|                 indexed_additions: IndexedAdditions { | ||||
|                     index_additions, | ||||
|                     ..Default::default() | ||||
|                 }, | ||||
|                 ..Default::default() | ||||
|             }); | ||||
|             db.lock() | ||||
|                 .unwrap() | ||||
|                 .stage(C::from(KeychainAdditions::from(index_additions))); | ||||
| 
 | ||||
|             // 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
 | ||||
| @ -396,15 +357,12 @@ where | ||||
|         Ok(_) => { | ||||
|             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,
 | ||||
|             // it's not a big deal since we can always find it again form
 | ||||
|             // blockchain.
 | ||||
|             db.lock().unwrap().stage(ChangeSet { | ||||
|                 indexed_additions, | ||||
|                 ..Default::default() | ||||
|             }); | ||||
|             db.lock().unwrap().stage(C::from(keychain_additions)); | ||||
|             Ok(()) | ||||
|         } | ||||
|         Err(e) => { | ||||
| @ -659,18 +617,18 @@ pub fn planned_utxos<A: Anchor, O: ChainOracle, K: Clone + bdk_tmp_plan::CanDeri | ||||
|         .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>>, | ||||
|     db: &Mutex<Database<A, X>>, | ||||
|     db: &Mutex<Database<C>>, | ||||
|     chain: &Mutex<O>, | ||||
|     keymap: &HashMap<DescriptorPublicKey, DescriptorSecretKey>, | ||||
|     network: Network, | ||||
|     broadcast: impl FnOnce(&Transaction) -> anyhow::Result<()>, | ||||
|     cmd: Commands<C>, | ||||
|     cmd: Commands<S>, | ||||
| ) -> anyhow::Result<()> | ||||
| where | ||||
|     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 { | ||||
|         Commands::ChainSpecific(_) => unreachable!("example code should handle this!"), | ||||
| @ -708,9 +666,9 @@ where | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| pub fn prepare_index<C: clap::Subcommand, SC: secp256k1::Signing>( | ||||
|     args: &Args<C>, | ||||
|     secp: &Secp256k1<SC>, | ||||
| pub fn prepare_index<S: clap::Subcommand, CTX: secp256k1::Signing>( | ||||
|     args: &Args<S>, | ||||
|     secp: &Secp256k1<CTX>, | ||||
| ) -> anyhow::Result<(KeychainTxOutIndex<Keychain>, KeyMap)> { | ||||
|     let mut index = KeychainTxOutIndex::<Keychain>::default(); | ||||
| 
 | ||||
| @ -732,18 +690,18 @@ pub fn prepare_index<C: clap::Subcommand, SC: secp256k1::Signing>( | ||||
| } | ||||
| 
 | ||||
| #[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_default_path: &str, | ||||
| ) -> anyhow::Result<( | ||||
|     Args<S>, | ||||
|     KeyMap, | ||||
|     Mutex<KeychainTxGraph<A>>, | ||||
|     Mutex<Database<'m, A, X>>, | ||||
|     X, | ||||
|     KeychainTxOutIndex<Keychain>, | ||||
|     Mutex<Database<'m, C>>, | ||||
|     C, | ||||
| )> | ||||
| where | ||||
|     ChangeSet<A, X>: Default + Append + Serialize + DeserializeOwned, | ||||
|     C: Default + Append + Serialize + DeserializeOwned, | ||||
| { | ||||
|     if std::env::var("BDK_DB_PATH").is_err() { | ||||
|         std::env::set_var("BDK_DB_PATH", db_default_path); | ||||
| @ -752,25 +710,19 @@ where | ||||
|     let secp = Secp256k1::default(); | ||||
|     let (index, keymap) = prepare_index(&args, &secp)?; | ||||
| 
 | ||||
|     let mut indexed_graph = IndexedTxGraph::<A, KeychainTxOutIndex<Keychain>>::new(index); | ||||
| 
 | ||||
|     let mut db_backend = | ||||
|         match Store::<'m, ChangeSet<A, X>>::new_from_path(db_magic, args.db_path.as_path()) { | ||||
|     let mut db_backend = match Store::<'m, C>::new_from_path(db_magic, &args.db_path) { | ||||
|         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)), | ||||
|     }; | ||||
| 
 | ||||
|     let ChangeSet { | ||||
|         indexed_additions, | ||||
|         extension, | ||||
|     } = db_backend.load_from_persistence()?; | ||||
|     indexed_graph.apply_additions(indexed_additions); | ||||
|     let init_changeset = db_backend.load_from_persistence()?; | ||||
| 
 | ||||
|     Ok(( | ||||
|         args, | ||||
|         keymap, | ||||
|         Mutex::new(indexed_graph), | ||||
|         index, | ||||
|         Mutex::new(Database::new(db_backend)), | ||||
|         extension, | ||||
|         init_changeset, | ||||
|     )) | ||||
| } | ||||
|  | ||||
| @ -6,8 +6,9 @@ use std::{ | ||||
| 
 | ||||
| use bdk_chain::{ | ||||
|     bitcoin::{Address, BlockHash, Network, OutPoint, Txid}, | ||||
|     indexed_tx_graph::IndexedAdditions, | ||||
|     local_chain::{self, LocalChain}, | ||||
|     indexed_tx_graph::{IndexedAdditions, IndexedTxGraph}, | ||||
|     keychain::LocalChangeSet, | ||||
|     local_chain::LocalChain, | ||||
|     Append, ConfirmationHeightAnchor, | ||||
| }; | ||||
| use bdk_electrum::{ | ||||
| @ -17,6 +18,7 @@ use bdk_electrum::{ | ||||
| use example_cli::{ | ||||
|     anyhow::{self, Context}, | ||||
|     clap::{self, Parser, Subcommand}, | ||||
|     Keychain, | ||||
| }; | ||||
| 
 | ||||
| const DB_MAGIC: &[u8] = b"bdk_example_electrum"; | ||||
| @ -59,15 +61,21 @@ pub struct ScanOptions { | ||||
|     pub batch_size: usize, | ||||
| } | ||||
| 
 | ||||
| type ChangeSet = LocalChangeSet<Keychain, ConfirmationHeightAnchor>; | ||||
| 
 | ||||
| fn main() -> anyhow::Result<()> { | ||||
|     let (args, keymap, graph, db, chain_changeset) = | ||||
|         example_cli::init::<ElectrumCommands, ConfirmationHeightAnchor, local_chain::ChangeSet>( | ||||
|             DB_MAGIC, DB_PATH, | ||||
|         )?; | ||||
|     let (args, keymap, index, db, init_changeset) = | ||||
|         example_cli::init::<ElectrumCommands, ChangeSet>(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 mut chain = LocalChain::default(); | ||||
|         chain.apply_changeset(chain_changeset); | ||||
|         chain.apply_changeset(init_changeset.chain_changeset); | ||||
|         chain | ||||
|     }); | ||||
| 
 | ||||
| @ -302,9 +310,9 @@ fn main() -> anyhow::Result<()> { | ||||
|             additions | ||||
|         }; | ||||
| 
 | ||||
|         example_cli::ChangeSet { | ||||
|         ChangeSet { | ||||
|             indexed_additions, | ||||
|             extension: chain_changeset, | ||||
|             chain_changeset, | ||||
|         } | ||||
|     }; | ||||
| 
 | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user