feat(wallet)!: change persist API to use StageExt and StageExtAsync
				
					
				
			This commit is contained in:
		
							parent
							
								
									2e40b0118c
								
							
						
					
					
						commit
						19328d4999
					
				| @ -30,6 +30,7 @@ js-sys = "0.3" | ||||
| [features] | ||||
| default = ["std"] | ||||
| std = ["bitcoin/std", "miniscript/std", "bdk_chain/std"] | ||||
| async = ["bdk_chain/async"] | ||||
| compiler = ["miniscript/compiler"] | ||||
| all-keys = ["keys-bip39"] | ||||
| keys-bip39 = ["bip39"] | ||||
|  | ||||
| @ -26,6 +26,7 @@ use bdk_chain::{ | ||||
|     local_chain::{ | ||||
|         self, ApplyHeaderError, CannotConnectError, CheckPoint, CheckPointIter, LocalChain, | ||||
|     }, | ||||
|     persist::{PersistBackend, StageExt}, | ||||
|     spk_client::{FullScanRequest, FullScanResult, SyncRequest, SyncResult}, | ||||
|     tx_graph::{CanonicalTx, TxGraph}, | ||||
|     Append, BlockId, ChainPosition, ConfirmationTime, ConfirmationTimeHeightAnchor, FullTxOut, | ||||
| @ -40,7 +41,6 @@ use bitcoin::{ | ||||
| use bitcoin::{consensus::encode::serialize, transaction, BlockHash, Psbt}; | ||||
| use bitcoin::{constants::genesis_block, Amount}; | ||||
| use core::fmt; | ||||
| use core::mem; | ||||
| use core::ops::Deref; | ||||
| use descriptor::error::Error as DescriptorError; | ||||
| use miniscript::psbt::{PsbtExt, PsbtInputExt, PsbtInputSatisfier}; | ||||
| @ -393,18 +393,6 @@ impl Wallet { | ||||
|         }) | ||||
|     } | ||||
| 
 | ||||
|     /// Stage a ['ChangeSet'] to be persisted later.
 | ||||
|     ///
 | ||||
|     /// [`commit`]: Self::commit
 | ||||
|     fn stage(&mut self, changeset: ChangeSet) { | ||||
|         self.stage.append(changeset) | ||||
|     } | ||||
| 
 | ||||
|     /// Take the staged [`ChangeSet`] to be persisted now.
 | ||||
|     pub fn take_staged(&mut self) -> ChangeSet { | ||||
|         mem::take(&mut self.stage) | ||||
|     } | ||||
| 
 | ||||
|     /// Load [`Wallet`] from the given previously persisted [`ChangeSet`].
 | ||||
|     ///
 | ||||
|     /// Note that the descriptor secret keys are not persisted to the db; this means that after
 | ||||
| @ -687,7 +675,7 @@ impl Wallet { | ||||
|     /// # let changeset = ChangeSet::default();
 | ||||
|     /// # let mut wallet = Wallet::load_from_changeset(changeset).expect("load wallet");
 | ||||
|     /// let next_address = wallet.reveal_next_address(KeychainKind::External);
 | ||||
|     /// db.write_changes(&wallet.take_staged())?;
 | ||||
|     /// wallet.commit_to(&mut db)?;
 | ||||
|     ///
 | ||||
|     /// // Now it's safe to show the user their next address!
 | ||||
|     /// println!("Next address: {}", next_address.address);
 | ||||
| @ -731,7 +719,7 @@ impl Wallet { | ||||
|             .reveal_to_target(&keychain, index) | ||||
|             .expect("keychain must exist"); | ||||
| 
 | ||||
|         self.stage(indexed_tx_graph::ChangeSet::from(index_changeset).into()); | ||||
|         self.stage.append(index_changeset.into()); | ||||
| 
 | ||||
|         spks.into_iter().map(move |(index, spk)| AddressInfo { | ||||
|             index, | ||||
| @ -915,7 +903,7 @@ impl Wallet { | ||||
|     /// [`list_output`]: Self::list_output
 | ||||
|     pub fn insert_txout(&mut self, outpoint: OutPoint, txout: TxOut) { | ||||
|         let additions = self.indexed_graph.insert_txout(outpoint, txout); | ||||
|         self.stage(ChangeSet::from(additions)); | ||||
|         self.stage.append(additions.into()); | ||||
|     } | ||||
| 
 | ||||
|     /// Calculates the fee of a given transaction. Returns [`Amount::ZERO`] if `tx` is a coinbase transaction.
 | ||||
| @ -1084,7 +1072,7 @@ impl Wallet { | ||||
|     ) -> Result<bool, local_chain::AlterCheckPointError> { | ||||
|         let changeset = self.chain.insert_block(block_id)?; | ||||
|         let changed = !changeset.is_empty(); | ||||
|         self.stage(changeset.into()); | ||||
|         self.stage.append(changeset.into()); | ||||
|         Ok(changed) | ||||
|     } | ||||
| 
 | ||||
| @ -1146,7 +1134,7 @@ impl Wallet { | ||||
|         } | ||||
| 
 | ||||
|         let changed = !changeset.is_empty(); | ||||
|         self.stage(changeset); | ||||
|         self.stage.append(changeset); | ||||
|         Ok(changed) | ||||
|     } | ||||
| 
 | ||||
| @ -1470,9 +1458,7 @@ impl Wallet { | ||||
|                     .next_unused_spk(&change_keychain) | ||||
|                     .expect("keychain must exist"); | ||||
|                 self.indexed_graph.index.mark_used(change_keychain, index); | ||||
|                 self.stage(ChangeSet::from(indexed_tx_graph::ChangeSet::from( | ||||
|                     index_changeset, | ||||
|                 ))); | ||||
|                 self.stage.append(index_changeset.into()); | ||||
|                 spk | ||||
|             } | ||||
|         }; | ||||
| @ -2291,16 +2277,52 @@ impl Wallet { | ||||
|             .indexed_graph | ||||
|             .index | ||||
|             .reveal_to_target_multi(&update.last_active_indices); | ||||
|         changeset.append(ChangeSet::from(indexed_tx_graph::ChangeSet::from( | ||||
|             index_changeset, | ||||
|         ))); | ||||
|         changeset.append(ChangeSet::from( | ||||
|             self.indexed_graph.apply_update(update.graph), | ||||
|         )); | ||||
|         self.stage(changeset); | ||||
|         changeset.append(index_changeset.into()); | ||||
|         changeset.append(self.indexed_graph.apply_update(update.graph).into()); | ||||
|         self.stage.append(changeset); | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
|     /// Commits all currently [`staged`](Wallet::staged) changes to the `persist_backend`.
 | ||||
|     ///
 | ||||
|     /// This returns whether anything was persisted.
 | ||||
|     ///
 | ||||
|     /// # Error
 | ||||
|     ///
 | ||||
|     /// Returns a backend-defined error if this fails.
 | ||||
|     pub fn commit_to<B>(&mut self, persist_backend: &mut B) -> Result<bool, B::WriteError> | ||||
|     where | ||||
|         B: PersistBackend<ChangeSet>, | ||||
|     { | ||||
|         let committed = StageExt::commit_to(&mut self.stage, persist_backend)?; | ||||
|         Ok(committed.is_some()) | ||||
|     } | ||||
| 
 | ||||
|     /// Commits all currently [`staged`](Wallet::staged) changes to the async `persist_backend`.
 | ||||
|     ///
 | ||||
|     /// This returns whether anything was persisted.
 | ||||
|     ///
 | ||||
|     /// # Error
 | ||||
|     ///
 | ||||
|     /// Returns a backend-defined error if this fails.
 | ||||
|     #[cfg(feature = "async")] | ||||
|     pub async fn commit_to_async<B>( | ||||
|         &mut self, | ||||
|         persist_backend: &mut B, | ||||
|     ) -> Result<bool, B::WriteError> | ||||
|     where | ||||
|         B: bdk_chain::persist::PersistBackendAsync<ChangeSet> + Send + Sync, | ||||
|     { | ||||
|         let committed = | ||||
|             bdk_chain::persist::StageExtAsync::commit_to(&mut self.stage, persist_backend).await?; | ||||
|         Ok(committed.is_some()) | ||||
|     } | ||||
| 
 | ||||
|     /// Get the staged [`ChangeSet`] that is yet to be committed.
 | ||||
|     pub fn staged(&self) -> &ChangeSet { | ||||
|         &self.stage | ||||
|     } | ||||
| 
 | ||||
|     /// Get a reference to the inner [`TxGraph`].
 | ||||
|     pub fn tx_graph(&self) -> &TxGraph<ConfirmationTimeHeightAnchor> { | ||||
|         self.indexed_graph.graph() | ||||
| @ -2370,7 +2392,7 @@ impl Wallet { | ||||
|                 .apply_block_relevant(block, height) | ||||
|                 .into(), | ||||
|         ); | ||||
|         self.stage(changeset); | ||||
|         self.stage.append(changeset); | ||||
|         Ok(()) | ||||
|     } | ||||
| 
 | ||||
| @ -2393,7 +2415,7 @@ impl Wallet { | ||||
|         let indexed_graph_changeset = self | ||||
|             .indexed_graph | ||||
|             .batch_insert_relevant_unconfirmed(unconfirmed_txs); | ||||
|         self.stage(ChangeSet::from(indexed_graph_changeset)); | ||||
|         self.stage.append(indexed_graph_changeset.into()); | ||||
|     } | ||||
| } | ||||
| 
 | ||||
|  | ||||
| @ -90,11 +90,10 @@ fn load_recovers_wallet() -> anyhow::Result<()> { | ||||
|             wallet.reveal_next_address(KeychainKind::External); | ||||
| 
 | ||||
|             // persist new wallet changes
 | ||||
|             let staged_changeset = wallet.take_staged(); | ||||
|             let db = &mut create_new(&file_path).expect("must create db"); | ||||
|             db.write_changes(&staged_changeset) | ||||
|             let mut db = create_new(&file_path).expect("must create db"); | ||||
|             wallet | ||||
|                 .commit_to(&mut db) | ||||
|                 .map_err(|e| anyhow!("write changes error: {}", e))?; | ||||
| 
 | ||||
|             wallet.spk_index().clone() | ||||
|         }; | ||||
| 
 | ||||
| @ -158,9 +157,9 @@ fn new_or_load() -> anyhow::Result<()> { | ||||
|         let wallet_keychains: BTreeMap<_, _> = { | ||||
|             let wallet = &mut Wallet::new_or_load(desc, change_desc, None, Network::Testnet) | ||||
|                 .expect("must init wallet"); | ||||
|             let staged_changeset = wallet.take_staged(); | ||||
|             let mut db = new_or_load(&file_path).expect("must create db"); | ||||
|             db.write_changes(&staged_changeset) | ||||
|             wallet | ||||
|                 .commit_to(&mut db) | ||||
|                 .map_err(|e| anyhow!("write changes error: {}", e))?; | ||||
|             wallet.keychains().map(|(k, v)| (*k, v.clone())).collect() | ||||
|         }; | ||||
|  | ||||
| @ -33,7 +33,7 @@ fn main() -> Result<(), anyhow::Error> { | ||||
|     )?; | ||||
| 
 | ||||
|     let address = wallet.next_unused_address(KeychainKind::External); | ||||
|     db.write_changes(&wallet.take_staged())?; | ||||
|     wallet.commit_to(&mut db)?; | ||||
|     println!("Generated Address: {}", address); | ||||
| 
 | ||||
|     let balance = wallet.balance(); | ||||
| @ -72,7 +72,7 @@ fn main() -> Result<(), anyhow::Error> { | ||||
|     println!(); | ||||
| 
 | ||||
|     wallet.apply_update(update)?; | ||||
|     db.write_changes(&wallet.take_staged())?; | ||||
|     wallet.commit_to(&mut db)?; | ||||
| 
 | ||||
|     let balance = wallet.balance(); | ||||
|     println!("Wallet balance after syncing: {} sats", balance.total()); | ||||
|  | ||||
| @ -30,7 +30,7 @@ async fn main() -> Result<(), anyhow::Error> { | ||||
|     )?; | ||||
| 
 | ||||
|     let address = wallet.next_unused_address(KeychainKind::External); | ||||
|     db.write_changes(&wallet.take_staged())?; | ||||
|     wallet.commit_to(&mut db)?; | ||||
|     println!("Generated Address: {}", address); | ||||
| 
 | ||||
|     let balance = wallet.balance(); | ||||
| @ -78,7 +78,7 @@ async fn main() -> Result<(), anyhow::Error> { | ||||
|     let _ = update.graph_update.update_last_seen_unconfirmed(now); | ||||
| 
 | ||||
|     wallet.apply_update(update)?; | ||||
|     db.write_changes(&wallet.take_staged())?; | ||||
|     wallet.commit_to(&mut db)?; | ||||
|     println!(); | ||||
| 
 | ||||
|     let balance = wallet.balance(); | ||||
|  | ||||
| @ -29,7 +29,7 @@ fn main() -> Result<(), anyhow::Error> { | ||||
|     )?; | ||||
| 
 | ||||
|     let address = wallet.next_unused_address(KeychainKind::External); | ||||
|     db.write_changes(&wallet.take_staged())?; | ||||
|     wallet.commit_to(&mut db)?; | ||||
|     println!("Generated Address: {}", address); | ||||
| 
 | ||||
|     let balance = wallet.balance(); | ||||
| @ -55,7 +55,7 @@ fn main() -> Result<(), anyhow::Error> { | ||||
|     let _ = update.graph_update.update_last_seen_unconfirmed(now); | ||||
| 
 | ||||
|     wallet.apply_update(update)?; | ||||
|     db.write_changes(&wallet.take_staged())?; | ||||
|     wallet.commit_to(&mut db)?; | ||||
|     println!(); | ||||
| 
 | ||||
|     let balance = wallet.balance(); | ||||
|  | ||||
| @ -147,7 +147,7 @@ fn main() -> anyhow::Result<()> { | ||||
|                 let connected_to = block_emission.connected_to(); | ||||
|                 let start_apply_block = Instant::now(); | ||||
|                 wallet.apply_block_connected_to(&block_emission.block, height, connected_to)?; | ||||
|                 db.write_changes(&wallet.take_staged())?; | ||||
|                 wallet.commit_to(&mut db)?; | ||||
|                 let elapsed = start_apply_block.elapsed().as_secs_f32(); | ||||
|                 println!( | ||||
|                     "Applied block {} at height {} in {}s", | ||||
| @ -157,7 +157,7 @@ fn main() -> anyhow::Result<()> { | ||||
|             Emission::Mempool(mempool_emission) => { | ||||
|                 let start_apply_mempool = Instant::now(); | ||||
|                 wallet.apply_unconfirmed_txs(mempool_emission.iter().map(|(tx, time)| (tx, *time))); | ||||
|                 db.write_changes(&wallet.take_staged())?; | ||||
|                 wallet.commit_to(&mut db)?; | ||||
|                 println!( | ||||
|                     "Applied unconfirmed transactions in {}s", | ||||
|                     start_apply_mempool.elapsed().as_secs_f32() | ||||
|  | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user