@@ -2341,101 +2341,118 @@ impl Wallet {
23412341 . to_string ( )
23422342 }
23432343
2344- /// Applies an update to the wallet, stages the changes, and returns events.
2344+ /// Applies an update to the wallet, stages changes, and returns events describing what changed .
23452345 ///
2346- /// Usually you create an `update` by interacting with some blockchain data source and inserting
2347- /// transactions related to your wallet into it. Staged changes are NOT persisted.
2346+ /// This is the primary method for updating wallet state with new blockchain data. It accepts
2347+ /// an [`Update`]
23482348 ///
2349- /// After applying updates, you should process the events in your app before persisting the
2350- /// staged wallet changes. For an example of how to persist staged wallet changes, see
2351- /// [`Wallet::reveal_next_address`].
2349+ /// **IMPORTANT**: Changes are staged but **NOT automatically persisted**. You must:
2350+ ///
2351+ /// 1. Process the returned events in your application
2352+ /// 2. Call [`take_staged`] to retrieve the [`ChangeSet`]
2353+ /// 3. Persist the changeset to your database/storage
2354+ ///
2355+ /// Failing to persist changes means they will be lost when the wallet is reloaded.
2356+ ///
2357+ /// # Example
2358+ ///
2359+ /// ## Basic usage with event handling
23522360 ///
23532361 /// ```rust,no_run
23542362 /// # use bitcoin::*;
23552363 /// # use bdk_wallet::*;
23562364 /// use bdk_wallet::event::WalletEvent;
23572365 /// # let wallet_update = Update::default();
23582366 /// # let mut wallet = doctest_wallet!();
2367+ ///
2368+ /// // Apply the update and get events
23592369 /// let events = wallet.apply_update(wallet_update)?;
2360- /// // Handle wallet relevant events from this update.
2361- /// events.iter().for_each(|event| {
2370+ ///
2371+ /// // Handle each event
2372+ /// for event in events {
23622373 /// match event {
2363- /// // The chain tip changed.
23642374 /// WalletEvent::ChainTipChanged { old_tip, new_tip } => {
2365- /// todo!() // handle event
2375+ /// println!(
2376+ /// "Chain advanced from {} to {}",
2377+ /// old_tip.height, new_tip.height
2378+ /// );
23662379 /// }
2367- /// // An unconfirmed tx is now confirmed in a block.
23682380 /// WalletEvent::TxConfirmed {
23692381 /// txid,
2370- /// tx,
23712382 /// block_time,
23722383 /// old_block_time: None,
2384+ /// ..
23732385 /// } => {
2374- /// todo!() // handle event
2386+ /// println!(
2387+ /// "Transaction {} confirmed at height {}",
2388+ /// txid, block_time.block_id.height
2389+ /// );
23752390 /// }
2376- /// // A confirmed tx is now confirmed in a new block (reorg).
23772391 /// WalletEvent::TxConfirmed {
23782392 /// txid,
2379- /// tx,
23802393 /// block_time,
2381- /// old_block_time: Some(old_block_time),
2394+ /// old_block_time: Some(old),
2395+ /// ..
23822396 /// } => {
2383- /// todo!() // handle event
2397+ /// println!(
2398+ /// "Transaction {} re-confirmed due to reorg: {} -> {}",
2399+ /// txid, old.block_id.height, block_time.block_id.height
2400+ /// );
23842401 /// }
2385- /// // A new unconfirmed tx was seen in the mempool.
23862402 /// WalletEvent::TxUnconfirmed {
23872403 /// txid,
2388- /// tx,
23892404 /// old_block_time: None,
2405+ /// ..
23902406 /// } => {
2391- /// todo!() // handle event
2407+ /// println!("New mempool transaction: {}", txid);
23922408 /// }
2393- /// // A previously confirmed tx in now unconfirmed in the mempool (reorg).
23942409 /// WalletEvent::TxUnconfirmed {
23952410 /// txid,
2396- /// tx ,
2397- /// old_block_time: Some(old_block_time),
2411+ /// old_block_time: Some(old) ,
2412+ /// ..
23982413 /// } => {
2399- /// todo!() // handle event
2414+ /// println!(
2415+ /// "Transaction {} unconfirmed due to reorg from height {}",
2416+ /// txid, old.block_id.height
2417+ /// );
24002418 /// }
2401- /// // An unconfirmed tx was replaced in the mempool (RBF or double spent input).
24022419 /// WalletEvent::TxReplaced {
2403- /// txid,
2404- /// tx,
2405- /// conflicts,
2420+ /// txid, conflicts, ..
24062421 /// } => {
2407- /// todo!() // handle event
2422+ /// println!("Transaction {} replaced: {:?}", txid, conflicts);
24082423 /// }
2409- /// // An unconfirmed tx was dropped from the mempool (fee too low).
2410- /// WalletEvent::TxDropped { txid, tx } => {
2411- /// todo!() // handle event
2412- /// }
2413- /// _ => {
2414- /// // unexpected event, do nothing
2424+ /// WalletEvent::TxDropped { txid, .. } => {
2425+ /// println!("Transaction {} dropped from mempool", txid);
24152426 /// }
24162427 /// }
2417- /// // take staged wallet changes
2418- /// let staged = wallet.take_staged();
2419- /// // persist staged changes
2420- /// });
2428+ /// }
2429+ ///
2430+ /// // IMPORTANT: Persist the changes
2431+ /// if let Some(changeset) = wallet.take_staged() {
2432+ /// // Save changeset to your database
2433+ /// // e.g., db.persist(&changeset)?;
2434+ /// }
24212435 /// # Ok::<(), anyhow::Error>(())
24222436 /// ```
2423- /// [`TxBuilder`]: crate::TxBuilder
2437+ ///
2438+ /// # See Also
2439+ ///
2440+ /// - [`apply_block`] - Apply a single block to the wallet
2441+ /// - [`apply_block_connected_to`] - Apply a block with explicit connection point
2442+ /// - [`take_staged`] - Retrieve staged changes for persistence
2443+ /// - [`WalletEvent`] - Documentation for all event types
2444+ /// - [`Update`] - The update structure accepted by this method
2445+ ///
2446+ /// [`apply_block`]: Wallet::apply_block
2447+ /// [`apply_block_connected_to`]: Wallet::apply_block_connected_to
2448+ /// [`take_staged`]: Wallet::take_staged
24242449 pub fn apply_update (
24252450 & mut self ,
24262451 update : impl Into < Update > ,
24272452 ) -> Result < Vec < WalletEvent > , CannotConnectError > {
24282453 // snapshot of chain tip and transactions before update
24292454 let chain_tip1 = self . chain . tip ( ) . block_id ( ) ;
2430- let wallet_txs1 = self
2431- . transactions ( )
2432- . map ( |wtx| {
2433- (
2434- wtx. tx_node . txid ,
2435- ( wtx. tx_node . tx . clone ( ) , wtx. chain_position ) ,
2436- )
2437- } )
2438- . collect :: < BTreeMap < Txid , ( Arc < Transaction > , ChainPosition < ConfirmationBlockTime > ) > > ( ) ;
2455+ let wallet_txs1 = self . collect_wallet_txs ( ) ;
24392456
24402457 // apply update
24412458 let update = update. into ( ) ;
@@ -2454,15 +2471,7 @@ impl Wallet {
24542471
24552472 // chain tip and transactions after update
24562473 let chain_tip2 = self . chain . tip ( ) . block_id ( ) ;
2457- let wallet_txs2 = self
2458- . transactions ( )
2459- . map ( |wtx| {
2460- (
2461- wtx. tx_node . txid ,
2462- ( wtx. tx_node . tx . clone ( ) , wtx. chain_position ) ,
2463- )
2464- } )
2465- . collect :: < BTreeMap < Txid , ( Arc < Transaction > , ChainPosition < ConfirmationBlockTime > ) > > ( ) ;
2474+ let wallet_txs2 = self . collect_wallet_txs ( ) ;
24662475
24672476 Ok ( wallet_events (
24682477 self ,
@@ -2557,7 +2566,9 @@ impl Wallet {
25572566 /// if you need the inserted block data to be reloaded after closing the wallet.
25582567 /// See [`Wallet::reveal_next_address`].
25592568 ///
2560- /// See [`apply_update_events`] for more information on the returned [`WalletEvent`]s.
2569+ /// See [`apply_update`] for more information on the returned [`WalletEvent`]s.
2570+ ///
2571+ /// [`apply_update`]: Wallet::apply_update
25612572 pub fn apply_block_connected_to (
25622573 & mut self ,
25632574 block : & Block ,
@@ -2566,15 +2577,7 @@ impl Wallet {
25662577 ) -> Result < Vec < WalletEvent > , ApplyHeaderError > {
25672578 // snapshot of chain tip and transactions before update
25682579 let chain_tip1 = self . chain . tip ( ) . block_id ( ) ;
2569- let wallet_txs1 = self
2570- . transactions ( )
2571- . map ( |wtx| {
2572- (
2573- wtx. tx_node . txid ,
2574- ( wtx. tx_node . tx . clone ( ) , wtx. chain_position ) ,
2575- )
2576- } )
2577- . collect :: < BTreeMap < Txid , ( Arc < Transaction > , ChainPosition < ConfirmationBlockTime > ) > > ( ) ;
2580+ let wallet_txs1 = self . collect_wallet_txs ( ) ;
25782581
25792582 // apply block to wallet
25802583 let mut changeset = ChangeSet :: default ( ) ;
@@ -2592,15 +2595,7 @@ impl Wallet {
25922595
25932596 // chain tip and transactions after update
25942597 let chain_tip2 = self . chain . tip ( ) . block_id ( ) ;
2595- let wallet_txs2 = self
2596- . transactions ( )
2597- . map ( |wtx| {
2598- (
2599- wtx. tx_node . txid ,
2600- ( wtx. tx_node . tx . clone ( ) , wtx. chain_position ) ,
2601- )
2602- } )
2603- . collect :: < BTreeMap < Txid , ( Arc < Transaction > , ChainPosition < ConfirmationBlockTime > ) > > ( ) ;
2598+ let wallet_txs2 = self . collect_wallet_txs ( ) ;
26042599
26052600 Ok ( wallet_events (
26062601 self ,
@@ -2611,13 +2606,30 @@ impl Wallet {
26112606 ) )
26122607 }
26132608
2609+ /// Collects all canonical wallet transactions into a map.
2610+ ///
2611+ /// This method is primarily used internally to create before/after snapshots when applying
2612+ /// updates or blocks to the wallet.
2613+ fn collect_wallet_txs (
2614+ & self ,
2615+ ) -> BTreeMap < Txid , ( Arc < Transaction > , ChainPosition < ConfirmationBlockTime > ) > {
2616+ self . transactions ( )
2617+ . map ( |wtx| {
2618+ (
2619+ wtx. tx_node . txid ,
2620+ ( wtx. tx_node . tx . clone ( ) , wtx. chain_position ) ,
2621+ )
2622+ } )
2623+ . collect ( )
2624+ }
2625+
26142626 /// Apply relevant unconfirmed transactions to the wallet.
26152627 ///
26162628 /// Transactions that are not relevant are filtered out.
26172629 ///
26182630 /// This method takes in an iterator of `(tx, last_seen)` where `last_seen` is the timestamp of
26192631 /// when the transaction was last seen in the mempool. This is used for conflict resolution
2620- /// when there is conflicting unconfirmed transactions. The transaction with the later
2632+ /// when there are conflicting unconfirmed transactions. The transaction with the later
26212633 /// `last_seen` is prioritized.
26222634 ///
26232635 /// **WARNING**: You must persist the changes resulting from one or more calls to this method
0 commit comments