bdk_core/tx_update.rs
1use crate::collections::{BTreeMap, BTreeSet, HashSet};
2use alloc::{sync::Arc, vec::Vec};
3use bitcoin::{OutPoint, Transaction, TxOut, Txid};
4
5/// Data object used to communicate updates about relevant transactions from some chain data source
6/// to the core model (usually a `bdk_chain::TxGraph`).
7///
8/// ```rust
9/// use bdk_core::TxUpdate;
10/// # use std::sync::Arc;
11/// # use bitcoin::{Transaction, transaction::Version, absolute::LockTime};
12/// # let version = Version::ONE;
13/// # let lock_time = LockTime::ZERO;
14/// # let tx = Arc::new(Transaction { input: vec![], output: vec![], version, lock_time });
15/// # let txid = tx.compute_txid();
16/// # let anchor = ();
17/// let mut tx_update = TxUpdate::default();
18/// tx_update.txs.push(tx);
19/// tx_update.anchors.insert((anchor, txid));
20/// ```
21#[derive(Debug, Clone)]
22#[non_exhaustive]
23pub struct TxUpdate<A = ()> {
24 /// Full transactions. These are transactions that were determined to be relevant to the wallet
25 /// given the request.
26 pub txs: Vec<Arc<Transaction>>,
27
28 /// Floating txouts. These are `TxOut`s that exist but the whole transaction wasn't included in
29 /// `txs` since only knowing about the output is important. These are often used to help
30 /// determine the fee of a wallet transaction.
31 pub txouts: BTreeMap<OutPoint, TxOut>,
32
33 /// Transaction anchors. Anchors tells us a position in the chain where a transaction was
34 /// confirmed.
35 pub anchors: BTreeSet<(A, Txid)>,
36
37 /// When transactions were seen in the mempool.
38 ///
39 /// An unconfirmed transaction can only be canonical with a `seen_at` value. It is the
40 /// responsibility of the chain-source to include the `seen_at` values for unconfirmed
41 /// (unanchored) transactions.
42 ///
43 /// [`FullScanRequest::start_time`](crate::spk_client::FullScanRequest::start_time) or
44 /// [`SyncRequest::start_time`](crate::spk_client::SyncRequest::start_time) can be used to
45 /// provide the `seen_at` value.
46 pub seen_ats: HashSet<(Txid, u64)>,
47
48 /// When transactions were discovered to be missing (evicted) from the mempool.
49 ///
50 /// [`SyncRequest::start_time`](crate::spk_client::SyncRequest::start_time) can be used to
51 /// provide the `evicted_at` value.
52 pub evicted_ats: HashSet<(Txid, u64)>,
53}
54
55impl<A> Default for TxUpdate<A> {
56 fn default() -> Self {
57 Self {
58 txs: Default::default(),
59 txouts: Default::default(),
60 anchors: Default::default(),
61 seen_ats: Default::default(),
62 evicted_ats: Default::default(),
63 }
64 }
65}
66
67impl<A> TxUpdate<A> {
68 /// Returns true if the `TxUpdate` contains no elements in any of its fields.
69 pub fn is_empty(&self) -> bool {
70 self.txs.is_empty()
71 && self.txouts.is_empty()
72 && self.anchors.is_empty()
73 && self.seen_ats.is_empty()
74 && self.evicted_ats.is_empty()
75 }
76}
77
78impl<A: Ord> TxUpdate<A> {
79 /// Transforms the [`TxUpdate`] to have `anchors` (`A`) of another type (`A2`).
80 ///
81 /// This takes in a closure with signature `FnMut(A) -> A2` which is called for each anchor to
82 /// transform it.
83 pub fn map_anchors<A2: Ord, F: FnMut(A) -> A2>(self, mut map: F) -> TxUpdate<A2> {
84 TxUpdate {
85 txs: self.txs,
86 txouts: self.txouts,
87 anchors: self
88 .anchors
89 .into_iter()
90 .map(|(a, txid)| (map(a), txid))
91 .collect(),
92 seen_ats: self.seen_ats,
93 evicted_ats: self.evicted_ats,
94 }
95 }
96
97 /// Extend this update with `other`.
98 pub fn extend(&mut self, other: TxUpdate<A>) {
99 self.txs.extend(other.txs);
100 self.txouts.extend(other.txouts);
101 self.anchors.extend(other.anchors);
102 self.seen_ats.extend(other.seen_ats);
103 self.evicted_ats.extend(other.evicted_ats);
104 }
105}