1use crate::collections::*;
123use crate::spk_txout::SpkTxOutIndex;
124use crate::BlockId;
125use crate::CanonicalIter;
126use crate::CanonicalReason;
127use crate::CanonicalizationParams;
128use crate::ObservedIn;
129use crate::{Anchor, Balance, ChainOracle, ChainPosition, FullTxOut, Merge};
130use alloc::collections::vec_deque::VecDeque;
131use alloc::sync::Arc;
132use alloc::vec::Vec;
133use bdk_core::ConfirmationBlockTime;
134pub use bdk_core::TxUpdate;
135use bitcoin::{Amount, OutPoint, ScriptBuf, SignedAmount, Transaction, TxOut, Txid};
136use core::fmt::{self, Formatter};
137use core::ops::RangeBounds;
138use core::{
139 convert::Infallible,
140 ops::{Deref, RangeInclusive},
141};
142
143impl<A: Ord> From<TxGraph<A>> for TxUpdate<A> {
144 fn from(graph: TxGraph<A>) -> Self {
145 let mut tx_update = TxUpdate::default();
146 tx_update.txs = graph.full_txs().map(|tx_node| tx_node.tx).collect();
147 tx_update.txouts = graph
148 .floating_txouts()
149 .map(|(op, txo)| (op, txo.clone()))
150 .collect();
151 tx_update.anchors = graph
152 .anchors
153 .into_iter()
154 .flat_map(|(txid, anchors)| anchors.into_iter().map(move |a| (a, txid)))
155 .collect();
156 tx_update.seen_ats = graph.last_seen.into_iter().collect();
157 tx_update.evicted_ats = graph.last_evicted.into_iter().collect();
158 tx_update
159 }
160}
161
162impl<A: Anchor> From<TxUpdate<A>> for TxGraph<A> {
163 fn from(update: TxUpdate<A>) -> Self {
164 let mut graph = TxGraph::<A>::default();
165 let _ = graph.apply_update(update);
166 graph
167 }
168}
169
170#[derive(Clone, Debug, PartialEq)]
176pub struct TxGraph<A = ConfirmationBlockTime> {
177 txs: HashMap<Txid, TxNodeInternal>,
178 spends: BTreeMap<OutPoint, HashSet<Txid>>,
179 anchors: HashMap<Txid, BTreeSet<A>>,
180 first_seen: HashMap<Txid, u64>,
181 last_seen: HashMap<Txid, u64>,
182 last_evicted: HashMap<Txid, u64>,
183
184 txs_by_highest_conf_heights: BTreeSet<(u32, Txid)>,
185 txs_by_last_seen: BTreeSet<(u64, Txid)>,
186
187 empty_outspends: HashSet<Txid>,
190 empty_anchors: BTreeSet<A>,
191}
192
193impl<A> Default for TxGraph<A> {
194 fn default() -> Self {
195 Self {
196 txs: Default::default(),
197 spends: Default::default(),
198 anchors: Default::default(),
199 first_seen: Default::default(),
200 last_seen: Default::default(),
201 last_evicted: Default::default(),
202 txs_by_highest_conf_heights: Default::default(),
203 txs_by_last_seen: Default::default(),
204 empty_outspends: Default::default(),
205 empty_anchors: Default::default(),
206 }
207 }
208}
209
210#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
212pub struct TxNode<'a, T, A> {
213 pub txid: Txid,
215 pub tx: T,
217 pub anchors: &'a BTreeSet<A>,
219 pub first_seen: Option<u64>,
221 pub last_seen: Option<u64>,
223}
224
225impl<T, A> Deref for TxNode<'_, T, A> {
226 type Target = T;
227
228 fn deref(&self) -> &Self::Target {
229 &self.tx
230 }
231}
232
233#[derive(Clone, Debug, PartialEq)]
238enum TxNodeInternal {
239 Whole(Arc<Transaction>),
240 Partial(BTreeMap<u32, TxOut>),
241}
242
243impl Default for TxNodeInternal {
244 fn default() -> Self {
245 Self::Partial(BTreeMap::new())
246 }
247}
248
249#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
251pub struct CanonicalTx<'a, T, A> {
252 pub chain_position: ChainPosition<A>,
254 pub tx_node: TxNode<'a, T, A>,
256}
257
258impl<'a, T, A> From<CanonicalTx<'a, T, A>> for Txid {
259 fn from(tx: CanonicalTx<'a, T, A>) -> Self {
260 tx.tx_node.txid
261 }
262}
263
264impl<'a, A> From<CanonicalTx<'a, Arc<Transaction>, A>> for Arc<Transaction> {
265 fn from(tx: CanonicalTx<'a, Arc<Transaction>, A>) -> Self {
266 tx.tx_node.tx
267 }
268}
269
270#[derive(Debug, PartialEq, Eq)]
272pub enum CalculateFeeError {
273 MissingTxOut(Vec<OutPoint>),
275 NegativeFee(SignedAmount),
277}
278
279impl fmt::Display for CalculateFeeError {
280 fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
281 match self {
282 CalculateFeeError::MissingTxOut(outpoints) => write!(
283 f,
284 "missing `TxOut` for one or more of the inputs of the tx: {:?}",
285 outpoints
286 ),
287 CalculateFeeError::NegativeFee(fee) => write!(
288 f,
289 "transaction is invalid according to the graph and has negative fee: {}",
290 fee.display_dynamic()
291 ),
292 }
293 }
294}
295
296#[cfg(feature = "std")]
297impl std::error::Error for CalculateFeeError {}
298
299impl<A> TxGraph<A> {
300 pub fn all_txouts(&self) -> impl Iterator<Item = (OutPoint, &TxOut)> {
304 self.txs.iter().flat_map(|(txid, tx)| match tx {
305 TxNodeInternal::Whole(tx) => tx
306 .as_ref()
307 .output
308 .iter()
309 .enumerate()
310 .map(|(vout, txout)| (OutPoint::new(*txid, vout as _), txout))
311 .collect::<Vec<_>>(),
312 TxNodeInternal::Partial(txouts) => txouts
313 .iter()
314 .map(|(vout, txout)| (OutPoint::new(*txid, *vout as _), txout))
315 .collect::<Vec<_>>(),
316 })
317 }
318
319 pub fn floating_txouts(&self) -> impl Iterator<Item = (OutPoint, &TxOut)> {
324 self.txs
325 .iter()
326 .filter_map(|(txid, tx_node)| match tx_node {
327 TxNodeInternal::Whole(_) => None,
328 TxNodeInternal::Partial(txouts) => Some(
329 txouts
330 .iter()
331 .map(|(&vout, txout)| (OutPoint::new(*txid, vout), txout)),
332 ),
333 })
334 .flatten()
335 }
336
337 pub fn full_txs(&self) -> impl Iterator<Item = TxNode<'_, Arc<Transaction>, A>> {
339 self.txs.iter().filter_map(|(&txid, tx)| match tx {
340 TxNodeInternal::Whole(tx) => Some(TxNode {
341 txid,
342 tx: tx.clone(),
343 anchors: self.anchors.get(&txid).unwrap_or(&self.empty_anchors),
344 first_seen: self.first_seen.get(&txid).copied(),
345 last_seen: self.last_seen.get(&txid).copied(),
346 }),
347 TxNodeInternal::Partial(_) => None,
348 })
349 }
350
351 pub fn txs_with_no_anchor_or_last_seen(
353 &self,
354 ) -> impl Iterator<Item = TxNode<'_, Arc<Transaction>, A>> {
355 self.full_txs().filter_map(|tx| {
356 if tx.anchors.is_empty() && tx.last_seen.is_none() {
357 Some(tx)
358 } else {
359 None
360 }
361 })
362 }
363
364 pub fn get_tx(&self, txid: Txid) -> Option<Arc<Transaction>> {
370 self.get_tx_node(txid).map(|n| n.tx)
371 }
372
373 pub fn get_tx_node(&self, txid: Txid) -> Option<TxNode<'_, Arc<Transaction>, A>> {
375 match &self.txs.get(&txid)? {
376 TxNodeInternal::Whole(tx) => Some(TxNode {
377 txid,
378 tx: tx.clone(),
379 anchors: self.anchors.get(&txid).unwrap_or(&self.empty_anchors),
380 first_seen: self.first_seen.get(&txid).copied(),
381 last_seen: self.last_seen.get(&txid).copied(),
382 }),
383 _ => None,
384 }
385 }
386
387 pub fn get_txout(&self, outpoint: OutPoint) -> Option<&TxOut> {
389 match &self.txs.get(&outpoint.txid)? {
390 TxNodeInternal::Whole(tx) => tx.as_ref().output.get(outpoint.vout as usize),
391 TxNodeInternal::Partial(txouts) => txouts.get(&outpoint.vout),
392 }
393 }
394
395 pub fn tx_outputs(&self, txid: Txid) -> Option<BTreeMap<u32, &TxOut>> {
399 Some(match &self.txs.get(&txid)? {
400 TxNodeInternal::Whole(tx) => tx
401 .as_ref()
402 .output
403 .iter()
404 .enumerate()
405 .map(|(vout, txout)| (vout as u32, txout))
406 .collect::<BTreeMap<_, _>>(),
407 TxNodeInternal::Partial(txouts) => txouts
408 .iter()
409 .map(|(vout, txout)| (*vout, txout))
410 .collect::<BTreeMap<_, _>>(),
411 })
412 }
413
414 pub fn calculate_fee(&self, tx: &Transaction) -> Result<Amount, CalculateFeeError> {
426 if tx.is_coinbase() {
427 return Ok(Amount::ZERO);
428 }
429
430 let (inputs_sum, missing_outputs) = tx.input.iter().fold(
431 (SignedAmount::ZERO, Vec::new()),
432 |(mut sum, mut missing_outpoints), txin| match self.get_txout(txin.previous_output) {
433 None => {
434 missing_outpoints.push(txin.previous_output);
435 (sum, missing_outpoints)
436 }
437 Some(txout) => {
438 sum += txout.value.to_signed().expect("valid `SignedAmount`");
439 (sum, missing_outpoints)
440 }
441 },
442 );
443 if !missing_outputs.is_empty() {
444 return Err(CalculateFeeError::MissingTxOut(missing_outputs));
445 }
446
447 let outputs_sum = tx
448 .output
449 .iter()
450 .map(|txout| txout.value.to_signed().expect("valid `SignedAmount`"))
451 .sum::<SignedAmount>();
452
453 let fee = inputs_sum - outputs_sum;
454 fee.to_unsigned()
455 .map_err(|_| CalculateFeeError::NegativeFee(fee))
456 }
457
458 pub fn outspends(&self, outpoint: OutPoint) -> &HashSet<Txid> {
463 self.spends.get(&outpoint).unwrap_or(&self.empty_outspends)
464 }
465
466 pub fn tx_spends(
473 &self,
474 txid: Txid,
475 ) -> impl DoubleEndedIterator<Item = (u32, &HashSet<Txid>)> + '_ {
476 let start = OutPoint::new(txid, 0);
477 let end = OutPoint::new(txid, u32::MAX);
478 self.spends
479 .range(start..=end)
480 .map(|(outpoint, spends)| (outpoint.vout, spends))
481 }
482}
483
484impl<A: Clone + Ord> TxGraph<A> {
485 pub fn walk_ancestors<'g, T, F, O>(&'g self, tx: T, walk_map: F) -> TxAncestors<'g, A, F, O>
499 where
500 T: Into<Arc<Transaction>>,
501 F: FnMut(usize, Arc<Transaction>) -> Option<O> + 'g,
502 {
503 TxAncestors::new_exclude_root(self, tx, walk_map)
504 }
505
506 pub fn walk_descendants<'g, F, O>(
517 &'g self,
518 txid: Txid,
519 walk_map: F,
520 ) -> TxDescendants<'g, A, F, O>
521 where
522 F: FnMut(usize, Txid) -> Option<O> + 'g,
523 {
524 TxDescendants::new_exclude_root(self, txid, walk_map)
525 }
526}
527
528impl<A> TxGraph<A> {
529 pub fn walk_conflicts<'g, F, O>(
534 &'g self,
535 tx: &'g Transaction,
536 walk_map: F,
537 ) -> TxDescendants<'g, A, F, O>
538 where
539 F: FnMut(usize, Txid) -> Option<O> + 'g,
540 {
541 let txids = self.direct_conflicts(tx).map(|(_, txid)| txid);
542 TxDescendants::from_multiple_include_root(self, txids, walk_map)
543 }
544
545 pub fn direct_conflicts<'g>(
553 &'g self,
554 tx: &'g Transaction,
555 ) -> impl Iterator<Item = (usize, Txid)> + 'g {
556 let txid = tx.compute_txid();
557 tx.input
558 .iter()
559 .enumerate()
560 .filter_map(move |(vin, txin)| self.spends.get(&txin.previous_output).zip(Some(vin)))
561 .flat_map(|(spends, vin)| core::iter::repeat(vin).zip(spends.iter().cloned()))
562 .filter(move |(_, conflicting_txid)| *conflicting_txid != txid)
563 }
564
565 pub fn all_anchors(&self) -> &HashMap<Txid, BTreeSet<A>> {
567 &self.anchors
568 }
569
570 pub fn is_empty(&self) -> bool {
572 self.txs.is_empty()
573 }
574}
575
576impl<A: Anchor> TxGraph<A> {
577 pub fn map_anchors<A2: Anchor, F>(self, f: F) -> TxGraph<A2>
582 where
583 F: FnMut(A) -> A2,
584 {
585 let mut new_graph = TxGraph::<A2>::default();
586 new_graph.apply_changeset(self.initial_changeset().map_anchors(f));
587 new_graph
588 }
589
590 pub fn new(txs: impl IntoIterator<Item = Transaction>) -> Self {
592 let mut new = Self::default();
593 for tx in txs.into_iter() {
594 let _ = new.insert_tx(tx);
595 }
596 new
597 }
598
599 pub fn insert_txout(&mut self, outpoint: OutPoint, txout: TxOut) -> ChangeSet<A> {
609 let mut changeset = ChangeSet::<A>::default();
610 let tx_node = self.txs.entry(outpoint.txid).or_default();
611 match tx_node {
612 TxNodeInternal::Whole(_) => {
613 }
618 TxNodeInternal::Partial(partial_tx) => {
619 match partial_tx.insert(outpoint.vout, txout.clone()) {
620 Some(old_txout) => {
621 debug_assert_eq!(
622 txout, old_txout,
623 "txout of the same outpoint should never change"
624 );
625 }
626 None => {
627 changeset.txouts.insert(outpoint, txout);
628 }
629 }
630 }
631 }
632 changeset
633 }
634
635 pub fn insert_tx<T: Into<Arc<Transaction>>>(&mut self, tx: T) -> ChangeSet<A> {
653 fn _merge_tx_witnesses(
655 original_tx: &Arc<Transaction>,
656 other_tx: &Arc<Transaction>,
657 ) -> Option<Arc<Transaction>> {
658 debug_assert_eq!(
659 original_tx.input.len(),
660 other_tx.input.len(),
661 "tx input count must be the same"
662 );
663 let merged_input = Iterator::zip(original_tx.input.iter(), other_tx.input.iter())
664 .map(|(original_txin, other_txin)| {
665 let original_key = core::cmp::Reverse((
666 original_txin.witness.is_empty(),
667 original_txin.witness.size(),
668 &original_txin.witness,
669 ));
670 let other_key = core::cmp::Reverse((
671 other_txin.witness.is_empty(),
672 other_txin.witness.size(),
673 &other_txin.witness,
674 ));
675 if original_key > other_key {
676 original_txin.clone()
677 } else {
678 other_txin.clone()
679 }
680 })
681 .collect::<Vec<_>>();
682 if merged_input == original_tx.input {
683 return None;
684 }
685 if merged_input == other_tx.input {
686 return Some(other_tx.clone());
687 }
688 Some(Arc::new(Transaction {
689 input: merged_input,
690 ..(**original_tx).clone()
691 }))
692 }
693
694 let tx: Arc<Transaction> = tx.into();
695 let txid = tx.compute_txid();
696 let mut changeset = ChangeSet::<A>::default();
697
698 let tx_node = self.txs.entry(txid).or_default();
699 match tx_node {
700 TxNodeInternal::Whole(existing_tx) => {
701 if existing_tx.as_ref() != tx.as_ref() {
702 if let Some(merged_tx) = _merge_tx_witnesses(existing_tx, &tx) {
704 *existing_tx = merged_tx.clone();
705 changeset.txs.insert(merged_tx);
706 }
707 }
708 }
709 partial_tx => {
710 for txin in &tx.input {
711 if txin.previous_output.is_null() {
713 continue;
714 }
715 self.spends
716 .entry(txin.previous_output)
717 .or_default()
718 .insert(txid);
719 }
720 *partial_tx = TxNodeInternal::Whole(tx.clone());
721 changeset.txs.insert(tx);
722 }
723 }
724
725 changeset
726 }
727
728 pub fn batch_insert_unconfirmed<T: Into<Arc<Transaction>>>(
734 &mut self,
735 txs: impl IntoIterator<Item = (T, u64)>,
736 ) -> ChangeSet<A> {
737 let mut changeset = ChangeSet::<A>::default();
738 for (tx, seen_at) in txs {
739 let tx: Arc<Transaction> = tx.into();
740 changeset.merge(self.insert_seen_at(tx.compute_txid(), seen_at));
741 changeset.merge(self.insert_tx(tx));
742 }
743 changeset
744 }
745
746 pub fn insert_anchor(&mut self, txid: Txid, anchor: A) -> ChangeSet<A> {
751 let mut old_top_h = None;
755 let mut new_top_h = anchor.confirmation_height_upper_bound();
756
757 let is_changed = match self.anchors.entry(txid) {
758 hash_map::Entry::Occupied(mut e) => {
759 old_top_h = e
760 .get()
761 .iter()
762 .last()
763 .map(Anchor::confirmation_height_upper_bound);
764 if let Some(old_top_h) = old_top_h {
765 if old_top_h > new_top_h {
766 new_top_h = old_top_h;
767 }
768 }
769 let is_changed = e.get_mut().insert(anchor.clone());
770 is_changed
771 }
772 hash_map::Entry::Vacant(e) => {
773 e.insert(core::iter::once(anchor.clone()).collect());
774 true
775 }
776 };
777
778 let mut changeset = ChangeSet::<A>::default();
779 if is_changed {
780 let new_top_is_changed = match old_top_h {
781 None => true,
782 Some(old_top_h) if old_top_h != new_top_h => true,
783 _ => false,
784 };
785 if new_top_is_changed {
786 if let Some(prev_top_h) = old_top_h {
787 self.txs_by_highest_conf_heights.remove(&(prev_top_h, txid));
788 }
789 self.txs_by_highest_conf_heights.insert((new_top_h, txid));
790 }
791 changeset.anchors.insert((anchor, txid));
792 }
793 changeset
794 }
795
796 pub fn insert_seen_at(&mut self, txid: Txid, seen_at: u64) -> ChangeSet<A> {
808 let mut changeset_first_seen = self.update_first_seen(txid, seen_at);
809 let changeset_last_seen = self.update_last_seen(txid, seen_at);
810 changeset_first_seen.merge(changeset_last_seen);
811 changeset_first_seen
812 }
813
814 fn update_first_seen(&mut self, txid: Txid, seen_at: u64) -> ChangeSet<A> {
816 let is_changed = match self.first_seen.entry(txid) {
817 hash_map::Entry::Occupied(mut e) => {
818 let first_seen = e.get_mut();
819 let change = *first_seen > seen_at;
820 if change {
821 *first_seen = seen_at;
822 }
823 change
824 }
825 hash_map::Entry::Vacant(e) => {
826 e.insert(seen_at);
827 true
828 }
829 };
830
831 let mut changeset = ChangeSet::<A>::default();
832 if is_changed {
833 changeset.first_seen.insert(txid, seen_at);
834 }
835 changeset
836 }
837
838 fn update_last_seen(&mut self, txid: Txid, seen_at: u64) -> ChangeSet<A> {
840 let mut old_last_seen = None;
841 let is_changed = match self.last_seen.entry(txid) {
842 hash_map::Entry::Occupied(mut e) => {
843 let last_seen = e.get_mut();
844 old_last_seen = Some(*last_seen);
845 let change = *last_seen < seen_at;
846 if change {
847 *last_seen = seen_at;
848 }
849 change
850 }
851 hash_map::Entry::Vacant(e) => {
852 e.insert(seen_at);
853 true
854 }
855 };
856
857 let mut changeset = ChangeSet::<A>::default();
858 if is_changed {
859 if let Some(old_last_seen) = old_last_seen {
860 self.txs_by_last_seen.remove(&(old_last_seen, txid));
861 }
862 self.txs_by_last_seen.insert((seen_at, txid));
863 changeset.last_seen.insert(txid, seen_at);
864 }
865 changeset
866 }
867
868 pub fn insert_evicted_at(&mut self, txid: Txid, evicted_at: u64) -> ChangeSet<A> {
874 let is_changed = match self.last_evicted.entry(txid) {
875 hash_map::Entry::Occupied(mut e) => {
876 let last_evicted = e.get_mut();
877 let change = *last_evicted < evicted_at;
878 if change {
879 *last_evicted = evicted_at;
880 }
881 change
882 }
883 hash_map::Entry::Vacant(e) => {
884 e.insert(evicted_at);
885 true
886 }
887 };
888
889 let mut changeset = ChangeSet::<A>::default();
890 if is_changed {
891 changeset.last_evicted.insert(txid, evicted_at);
892 }
893 changeset
894 }
895
896 pub fn batch_insert_relevant_evicted_at(
903 &mut self,
904 evicted_ats: impl IntoIterator<Item = (Txid, u64)>,
905 ) -> ChangeSet<A> {
906 let mut changeset = ChangeSet::default();
907 for (txid, evicted_at) in evicted_ats {
908 if self.txs.contains_key(&txid) {
910 changeset.merge(self.insert_evicted_at(txid, evicted_at));
911 }
912 }
913 changeset
914 }
915
916 pub fn apply_update(&mut self, update: TxUpdate<A>) -> ChangeSet<A> {
921 let mut changeset = ChangeSet::<A>::default();
922 for tx in update.txs {
923 changeset.merge(self.insert_tx(tx));
924 }
925 for (outpoint, txout) in update.txouts {
926 changeset.merge(self.insert_txout(outpoint, txout));
927 }
928 for (anchor, txid) in update.anchors {
929 changeset.merge(self.insert_anchor(txid, anchor));
930 }
931 for (txid, seen_at) in update.seen_ats {
932 changeset.merge(self.insert_seen_at(txid, seen_at));
933 }
934 for (txid, evicted_at) in update.evicted_ats {
935 changeset.merge(self.insert_evicted_at(txid, evicted_at));
936 }
937 changeset
938 }
939
940 pub fn initial_changeset(&self) -> ChangeSet<A> {
942 ChangeSet {
943 txs: self.full_txs().map(|tx_node| tx_node.tx).collect(),
944 txouts: self
945 .floating_txouts()
946 .map(|(op, txout)| (op, txout.clone()))
947 .collect(),
948 anchors: self
949 .anchors
950 .iter()
951 .flat_map(|(txid, anchors)| anchors.iter().map(|a| (a.clone(), *txid)))
952 .collect(),
953 first_seen: self.first_seen.iter().map(|(&k, &v)| (k, v)).collect(),
954 last_seen: self.last_seen.iter().map(|(&k, &v)| (k, v)).collect(),
955 last_evicted: self.last_evicted.iter().map(|(&k, &v)| (k, v)).collect(),
956 }
957 }
958
959 pub fn apply_changeset(&mut self, changeset: ChangeSet<A>) {
961 for tx in changeset.txs {
962 let _ = self.insert_tx(tx);
963 }
964 for (outpoint, txout) in changeset.txouts {
965 let _ = self.insert_txout(outpoint, txout);
966 }
967 for (anchor, txid) in changeset.anchors {
968 let _ = self.insert_anchor(txid, anchor);
969 }
970 for (txid, seen_at) in changeset.last_seen {
971 let _ = self.insert_seen_at(txid, seen_at);
972 }
973 for (txid, evicted_at) in changeset.last_evicted {
974 let _ = self.insert_evicted_at(txid, evicted_at);
975 }
976 }
977}
978
979impl<A: Anchor> TxGraph<A> {
980 pub fn try_list_canonical_txs<'a, C: ChainOracle + 'a>(
994 &'a self,
995 chain: &'a C,
996 chain_tip: BlockId,
997 params: CanonicalizationParams,
998 ) -> impl Iterator<Item = Result<CanonicalTx<'a, Arc<Transaction>, A>, C::Error>> {
999 fn find_direct_anchor<A: Anchor, C: ChainOracle>(
1000 tx_node: &TxNode<'_, Arc<Transaction>, A>,
1001 chain: &C,
1002 chain_tip: BlockId,
1003 ) -> Result<Option<A>, C::Error> {
1004 tx_node
1005 .anchors
1006 .iter()
1007 .find_map(|a| -> Option<Result<A, C::Error>> {
1008 match chain.is_block_in_chain(a.anchor_block(), chain_tip) {
1009 Ok(Some(true)) => Some(Ok(a.clone())),
1010 Ok(Some(false)) | Ok(None) => None,
1011 Err(err) => Some(Err(err)),
1012 }
1013 })
1014 .transpose()
1015 }
1016 self.canonical_iter(chain, chain_tip, params)
1017 .flat_map(move |res| {
1018 res.map(|(txid, _, canonical_reason)| {
1019 let tx_node = self.get_tx_node(txid).expect("must contain tx");
1020 let chain_position = match canonical_reason {
1021 CanonicalReason::Assumed { descendant } => match descendant {
1022 Some(_) => match find_direct_anchor(&tx_node, chain, chain_tip)? {
1023 Some(anchor) => ChainPosition::Confirmed {
1024 anchor,
1025 transitively: None,
1026 },
1027 None => ChainPosition::Unconfirmed {
1028 first_seen: tx_node.first_seen,
1029 last_seen: tx_node.last_seen,
1030 },
1031 },
1032 None => ChainPosition::Unconfirmed {
1033 first_seen: tx_node.first_seen,
1034 last_seen: tx_node.last_seen,
1035 },
1036 },
1037 CanonicalReason::Anchor { anchor, descendant } => match descendant {
1038 Some(_) => match find_direct_anchor(&tx_node, chain, chain_tip)? {
1039 Some(anchor) => ChainPosition::Confirmed {
1040 anchor,
1041 transitively: None,
1042 },
1043 None => ChainPosition::Confirmed {
1044 anchor,
1045 transitively: descendant,
1046 },
1047 },
1048 None => ChainPosition::Confirmed {
1049 anchor,
1050 transitively: None,
1051 },
1052 },
1053 CanonicalReason::ObservedIn { observed_in, .. } => match observed_in {
1054 ObservedIn::Mempool(last_seen) => ChainPosition::Unconfirmed {
1055 first_seen: tx_node.first_seen,
1056 last_seen: Some(last_seen),
1057 },
1058 ObservedIn::Block(_) => ChainPosition::Unconfirmed {
1059 first_seen: tx_node.first_seen,
1060 last_seen: None,
1061 },
1062 },
1063 };
1064 Ok(CanonicalTx {
1065 chain_position,
1066 tx_node,
1067 })
1068 })
1069 })
1070 }
1071
1072 pub fn list_canonical_txs<'a, C: ChainOracle<Error = Infallible> + 'a>(
1078 &'a self,
1079 chain: &'a C,
1080 chain_tip: BlockId,
1081 params: CanonicalizationParams,
1082 ) -> impl Iterator<Item = CanonicalTx<'a, Arc<Transaction>, A>> {
1083 self.try_list_canonical_txs(chain, chain_tip, params)
1084 .map(|res| res.expect("infallible"))
1085 }
1086
1087 pub fn try_filter_chain_txouts<'a, C: ChainOracle + 'a, OI: Clone + 'a>(
1107 &'a self,
1108 chain: &'a C,
1109 chain_tip: BlockId,
1110 params: CanonicalizationParams,
1111 outpoints: impl IntoIterator<Item = (OI, OutPoint)> + 'a,
1112 ) -> Result<impl Iterator<Item = (OI, FullTxOut<A>)> + 'a, C::Error> {
1113 let mut canon_txs = HashMap::<Txid, CanonicalTx<Arc<Transaction>, A>>::new();
1114 let mut canon_spends = HashMap::<OutPoint, Txid>::new();
1115 for r in self.try_list_canonical_txs(chain, chain_tip, params) {
1116 let canonical_tx = r?;
1117 let txid = canonical_tx.tx_node.txid;
1118
1119 if !canonical_tx.tx_node.tx.is_coinbase() {
1120 for txin in &canonical_tx.tx_node.tx.input {
1121 let _res = canon_spends.insert(txin.previous_output, txid);
1122 assert!(
1123 _res.is_none(),
1124 "tried to replace {:?} with {:?}",
1125 _res,
1126 txid
1127 );
1128 }
1129 }
1130 canon_txs.insert(txid, canonical_tx);
1131 }
1132 Ok(outpoints.into_iter().filter_map(move |(spk_i, outpoint)| {
1133 let canon_tx = canon_txs.get(&outpoint.txid)?;
1134 let txout = canon_tx
1135 .tx_node
1136 .tx
1137 .output
1138 .get(outpoint.vout as usize)
1139 .cloned()?;
1140 let chain_position = canon_tx.chain_position.clone();
1141 let spent_by = canon_spends.get(&outpoint).map(|spend_txid| {
1142 let spend_tx = canon_txs
1143 .get(spend_txid)
1144 .cloned()
1145 .expect("must be canonical");
1146 (spend_tx.chain_position, *spend_txid)
1147 });
1148 let is_on_coinbase = canon_tx.tx_node.is_coinbase();
1149 Some((
1150 spk_i,
1151 FullTxOut {
1152 outpoint,
1153 txout,
1154 chain_position,
1155 spent_by,
1156 is_on_coinbase,
1157 },
1158 ))
1159 }))
1160 }
1161
1162 pub fn txids_by_descending_anchor_height(
1167 &self,
1168 ) -> impl ExactSizeIterator<Item = (u32, Txid)> + '_ {
1169 self.txs_by_highest_conf_heights.iter().copied().rev()
1170 }
1171
1172 pub fn txids_by_descending_last_seen(&self) -> impl Iterator<Item = (u64, Txid)> + '_ {
1177 self.txs_by_last_seen
1178 .iter()
1179 .copied()
1180 .rev()
1181 .filter(|(last_seen, txid)| match self.last_evicted.get(txid) {
1182 Some(last_evicted) => last_evicted < last_seen,
1183 None => true,
1184 })
1185 }
1186
1187 pub fn canonical_iter<'a, C: ChainOracle>(
1189 &'a self,
1190 chain: &'a C,
1191 chain_tip: BlockId,
1192 params: CanonicalizationParams,
1193 ) -> CanonicalIter<'a, A, C> {
1194 CanonicalIter::new(self, chain, chain_tip, params)
1195 }
1196
1197 pub fn filter_chain_txouts<'a, C: ChainOracle<Error = Infallible> + 'a, OI: Clone + 'a>(
1204 &'a self,
1205 chain: &'a C,
1206 chain_tip: BlockId,
1207 params: CanonicalizationParams,
1208 outpoints: impl IntoIterator<Item = (OI, OutPoint)> + 'a,
1209 ) -> impl Iterator<Item = (OI, FullTxOut<A>)> + 'a {
1210 self.try_filter_chain_txouts(chain, chain_tip, params, outpoints)
1211 .expect("oracle is infallible")
1212 }
1213
1214 pub fn try_filter_chain_unspents<'a, C: ChainOracle + 'a, OI: Clone + 'a>(
1233 &'a self,
1234 chain: &'a C,
1235 chain_tip: BlockId,
1236 params: CanonicalizationParams,
1237 outpoints: impl IntoIterator<Item = (OI, OutPoint)> + 'a,
1238 ) -> Result<impl Iterator<Item = (OI, FullTxOut<A>)> + 'a, C::Error> {
1239 Ok(self
1240 .try_filter_chain_txouts(chain, chain_tip, params, outpoints)?
1241 .filter(|(_, full_txo)| full_txo.spent_by.is_none()))
1242 }
1243
1244 pub fn filter_chain_unspents<'a, C: ChainOracle<Error = Infallible> + 'a, OI: Clone + 'a>(
1251 &'a self,
1252 chain: &'a C,
1253 chain_tip: BlockId,
1254 params: CanonicalizationParams,
1255 txouts: impl IntoIterator<Item = (OI, OutPoint)> + 'a,
1256 ) -> impl Iterator<Item = (OI, FullTxOut<A>)> + 'a {
1257 self.try_filter_chain_unspents(chain, chain_tip, params, txouts)
1258 .expect("oracle is infallible")
1259 }
1260
1261 pub fn try_balance<C: ChainOracle, OI: Clone>(
1274 &self,
1275 chain: &C,
1276 chain_tip: BlockId,
1277 params: CanonicalizationParams,
1278 outpoints: impl IntoIterator<Item = (OI, OutPoint)>,
1279 mut trust_predicate: impl FnMut(&OI, ScriptBuf) -> bool,
1280 ) -> Result<Balance, C::Error> {
1281 let mut immature = Amount::ZERO;
1282 let mut trusted_pending = Amount::ZERO;
1283 let mut untrusted_pending = Amount::ZERO;
1284 let mut confirmed = Amount::ZERO;
1285
1286 for (spk_i, txout) in self.try_filter_chain_unspents(chain, chain_tip, params, outpoints)? {
1287 match &txout.chain_position {
1288 ChainPosition::Confirmed { .. } => {
1289 if txout.is_confirmed_and_spendable(chain_tip.height) {
1290 confirmed += txout.txout.value;
1291 } else if !txout.is_mature(chain_tip.height) {
1292 immature += txout.txout.value;
1293 }
1294 }
1295 ChainPosition::Unconfirmed { .. } => {
1296 if trust_predicate(&spk_i, txout.txout.script_pubkey) {
1297 trusted_pending += txout.txout.value;
1298 } else {
1299 untrusted_pending += txout.txout.value;
1300 }
1301 }
1302 }
1303 }
1304
1305 Ok(Balance {
1306 immature,
1307 trusted_pending,
1308 untrusted_pending,
1309 confirmed,
1310 })
1311 }
1312
1313 pub fn balance<C: ChainOracle<Error = Infallible>, OI: Clone>(
1319 &self,
1320 chain: &C,
1321 chain_tip: BlockId,
1322 params: CanonicalizationParams,
1323 outpoints: impl IntoIterator<Item = (OI, OutPoint)>,
1324 trust_predicate: impl FnMut(&OI, ScriptBuf) -> bool,
1325 ) -> Balance {
1326 self.try_balance(chain, chain_tip, params, outpoints, trust_predicate)
1327 .expect("oracle is infallible")
1328 }
1329
1330 pub fn try_list_expected_spk_txids<'a, C, I>(
1346 &'a self,
1347 chain: &'a C,
1348 chain_tip: BlockId,
1349 indexer: &'a impl AsRef<SpkTxOutIndex<I>>,
1350 spk_index_range: impl RangeBounds<I> + 'a,
1351 ) -> impl Iterator<Item = Result<(ScriptBuf, Txid), C::Error>> + 'a
1352 where
1353 C: ChainOracle,
1354 I: fmt::Debug + Clone + Ord + 'a,
1355 {
1356 let indexer = indexer.as_ref();
1357 self.try_list_canonical_txs(chain, chain_tip, CanonicalizationParams::default())
1358 .flat_map(move |res| -> Vec<Result<(ScriptBuf, Txid), C::Error>> {
1359 let range = &spk_index_range;
1360 let c_tx = match res {
1361 Ok(c_tx) => c_tx,
1362 Err(err) => return vec![Err(err)],
1363 };
1364 let relevant_spks = indexer.relevant_spks_of_tx(&c_tx.tx_node);
1365 relevant_spks
1366 .into_iter()
1367 .filter(|(i, _)| range.contains(i))
1368 .map(|(_, spk)| Ok((spk, c_tx.tx_node.txid)))
1369 .collect()
1370 })
1371 }
1372
1373 pub fn list_expected_spk_txids<'a, C, I>(
1378 &'a self,
1379 chain: &'a C,
1380 chain_tip: BlockId,
1381 indexer: &'a impl AsRef<SpkTxOutIndex<I>>,
1382 spk_index_range: impl RangeBounds<I> + 'a,
1383 ) -> impl Iterator<Item = (ScriptBuf, Txid)> + 'a
1384 where
1385 C: ChainOracle<Error = Infallible>,
1386 I: fmt::Debug + Clone + Ord + 'a,
1387 {
1388 self.try_list_expected_spk_txids(chain, chain_tip, indexer, spk_index_range)
1389 .map(|r| r.expect("infallible"))
1390 }
1391
1392 pub fn from_changeset(changeset: ChangeSet<A>) -> Self {
1394 let mut graph = Self::default();
1395 graph.apply_changeset(changeset);
1396 graph
1397 }
1398}
1399
1400#[derive(Debug, Clone, PartialEq)]
1409#[cfg_attr(
1410 feature = "serde",
1411 derive(serde::Deserialize, serde::Serialize),
1412 serde(bound(
1413 deserialize = "A: Ord + serde::Deserialize<'de>",
1414 serialize = "A: Ord + serde::Serialize",
1415 ))
1416)]
1417#[must_use]
1418pub struct ChangeSet<A = ()> {
1419 pub txs: BTreeSet<Arc<Transaction>>,
1421 pub txouts: BTreeMap<OutPoint, TxOut>,
1423 pub anchors: BTreeSet<(A, Txid)>,
1425 pub last_seen: BTreeMap<Txid, u64>,
1427 #[cfg_attr(feature = "serde", serde(default))]
1429 pub last_evicted: BTreeMap<Txid, u64>,
1430 #[cfg_attr(feature = "serde", serde(default))]
1432 pub first_seen: BTreeMap<Txid, u64>,
1433}
1434
1435impl<A> Default for ChangeSet<A> {
1436 fn default() -> Self {
1437 Self {
1438 txs: Default::default(),
1439 txouts: Default::default(),
1440 anchors: Default::default(),
1441 first_seen: Default::default(),
1442 last_seen: Default::default(),
1443 last_evicted: Default::default(),
1444 }
1445 }
1446}
1447
1448impl<A> ChangeSet<A> {
1449 pub fn txouts(&self) -> impl Iterator<Item = (OutPoint, &TxOut)> {
1451 self.txs
1452 .iter()
1453 .flat_map(|tx| {
1454 tx.output
1455 .iter()
1456 .enumerate()
1457 .map(move |(vout, txout)| (OutPoint::new(tx.compute_txid(), vout as _), txout))
1458 })
1459 .chain(self.txouts.iter().map(|(op, txout)| (*op, txout)))
1460 }
1461
1462 pub fn anchor_heights(&self) -> impl Iterator<Item = u32> + '_
1467 where
1468 A: Anchor,
1469 {
1470 let mut dedup = None;
1471 self.anchors
1472 .iter()
1473 .map(|(a, _)| a.anchor_block().height)
1474 .filter(move |height| {
1475 let duplicate = dedup == Some(*height);
1476 dedup = Some(*height);
1477 !duplicate
1478 })
1479 }
1480}
1481
1482impl<A: Ord> Merge for ChangeSet<A> {
1483 fn merge(&mut self, other: Self) {
1484 self.txs.extend(other.txs);
1487 self.txouts.extend(other.txouts);
1488 self.anchors.extend(other.anchors);
1489
1490 self.first_seen.extend(
1492 other
1493 .first_seen
1494 .into_iter()
1495 .filter(|(txid, update_fs)| match self.first_seen.get(txid) {
1496 Some(existing) => update_fs < existing,
1497 None => true,
1498 })
1499 .collect::<Vec<_>>(),
1500 );
1501
1502 self.last_seen.extend(
1504 other
1505 .last_seen
1506 .into_iter()
1507 .filter(|(txid, update_ls)| self.last_seen.get(txid) < Some(update_ls))
1508 .collect::<Vec<_>>(),
1509 );
1510 self.last_evicted.extend(
1512 other
1513 .last_evicted
1514 .into_iter()
1515 .filter(|(txid, update_lm)| self.last_evicted.get(txid) < Some(update_lm))
1516 .collect::<Vec<_>>(),
1517 );
1518 }
1519
1520 fn is_empty(&self) -> bool {
1521 self.txs.is_empty()
1522 && self.txouts.is_empty()
1523 && self.anchors.is_empty()
1524 && self.first_seen.is_empty()
1525 && self.last_seen.is_empty()
1526 && self.last_evicted.is_empty()
1527 }
1528}
1529
1530impl<A: Ord> ChangeSet<A> {
1531 pub fn map_anchors<A2: Ord, F>(self, mut f: F) -> ChangeSet<A2>
1536 where
1537 F: FnMut(A) -> A2,
1538 {
1539 ChangeSet {
1540 txs: self.txs,
1541 txouts: self.txouts,
1542 anchors: BTreeSet::<(A2, Txid)>::from_iter(
1543 self.anchors.into_iter().map(|(a, txid)| (f(a), txid)),
1544 ),
1545 first_seen: self.first_seen,
1546 last_seen: self.last_seen,
1547 last_evicted: self.last_evicted,
1548 }
1549 }
1550}
1551
1552impl<A> AsRef<TxGraph<A>> for TxGraph<A> {
1553 fn as_ref(&self) -> &TxGraph<A> {
1554 self
1555 }
1556}
1557
1558pub struct TxAncestors<'g, A, F, O>
1566where
1567 F: FnMut(usize, Arc<Transaction>) -> Option<O>,
1568{
1569 graph: &'g TxGraph<A>,
1570 visited: HashSet<Txid>,
1571 queue: VecDeque<(usize, Arc<Transaction>)>,
1572 filter_map: F,
1573}
1574
1575impl<'g, A, F, O> TxAncestors<'g, A, F, O>
1576where
1577 F: FnMut(usize, Arc<Transaction>) -> Option<O>,
1578{
1579 pub(crate) fn new_include_root(
1581 graph: &'g TxGraph<A>,
1582 tx: impl Into<Arc<Transaction>>,
1583 filter_map: F,
1584 ) -> Self {
1585 Self {
1586 graph,
1587 visited: Default::default(),
1588 queue: [(0, tx.into())].into(),
1589 filter_map,
1590 }
1591 }
1592
1593 pub(crate) fn new_exclude_root(
1595 graph: &'g TxGraph<A>,
1596 tx: impl Into<Arc<Transaction>>,
1597 filter_map: F,
1598 ) -> Self {
1599 let mut ancestors = Self {
1600 graph,
1601 visited: Default::default(),
1602 queue: Default::default(),
1603 filter_map,
1604 };
1605 ancestors.populate_queue(1, tx.into());
1606 ancestors
1607 }
1608
1609 #[allow(unused)]
1612 pub(crate) fn from_multiple_include_root<I>(
1613 graph: &'g TxGraph<A>,
1614 txs: I,
1615 filter_map: F,
1616 ) -> Self
1617 where
1618 I: IntoIterator,
1619 I::Item: Into<Arc<Transaction>>,
1620 {
1621 Self {
1622 graph,
1623 visited: Default::default(),
1624 queue: txs.into_iter().map(|tx| (0, tx.into())).collect(),
1625 filter_map,
1626 }
1627 }
1628
1629 #[allow(unused)]
1632 pub(crate) fn from_multiple_exclude_root<I>(
1633 graph: &'g TxGraph<A>,
1634 txs: I,
1635 filter_map: F,
1636 ) -> Self
1637 where
1638 I: IntoIterator,
1639 I::Item: Into<Arc<Transaction>>,
1640 {
1641 let mut ancestors = Self {
1642 graph,
1643 visited: Default::default(),
1644 queue: Default::default(),
1645 filter_map,
1646 };
1647 for tx in txs {
1648 ancestors.populate_queue(1, tx.into());
1649 }
1650 ancestors
1651 }
1652
1653 pub fn run_until_finished(self) {
1655 self.for_each(|_| {})
1656 }
1657
1658 fn populate_queue(&mut self, depth: usize, tx: Arc<Transaction>) {
1659 let ancestors = tx
1660 .input
1661 .iter()
1662 .map(|txin| txin.previous_output.txid)
1663 .filter(|&prev_txid| self.visited.insert(prev_txid))
1664 .filter_map(|prev_txid| self.graph.get_tx(prev_txid))
1665 .map(|tx| (depth, tx));
1666 self.queue.extend(ancestors);
1667 }
1668}
1669
1670impl<A, F, O> Iterator for TxAncestors<'_, A, F, O>
1671where
1672 F: FnMut(usize, Arc<Transaction>) -> Option<O>,
1673{
1674 type Item = O;
1675
1676 fn next(&mut self) -> Option<Self::Item> {
1677 loop {
1678 let (ancestor_depth, tx) = self.queue.pop_front()?;
1680 let item = match (self.filter_map)(ancestor_depth, tx.clone()) {
1682 Some(item) => item,
1683 None => continue,
1684 };
1685 self.populate_queue(ancestor_depth + 1, tx);
1686 return Some(item);
1687 }
1688 }
1689}
1690
1691pub struct TxDescendants<'g, A, F, O>
1697where
1698 F: FnMut(usize, Txid) -> Option<O>,
1699{
1700 graph: &'g TxGraph<A>,
1701 visited: HashSet<Txid>,
1702 queue: VecDeque<(usize, Txid)>,
1703 filter_map: F,
1704}
1705
1706impl<'g, A, F, O> TxDescendants<'g, A, F, O>
1707where
1708 F: FnMut(usize, Txid) -> Option<O>,
1709{
1710 #[allow(unused)]
1712 pub(crate) fn new_include_root(graph: &'g TxGraph<A>, txid: Txid, filter_map: F) -> Self {
1713 Self {
1714 graph,
1715 visited: Default::default(),
1716 queue: [(0, txid)].into(),
1717 filter_map,
1718 }
1719 }
1720
1721 pub(crate) fn new_exclude_root(graph: &'g TxGraph<A>, txid: Txid, filter_map: F) -> Self {
1723 let mut descendants = Self {
1724 graph,
1725 visited: Default::default(),
1726 queue: Default::default(),
1727 filter_map,
1728 };
1729 descendants.populate_queue(1, txid);
1730 descendants
1731 }
1732
1733 pub(crate) fn from_multiple_include_root<I>(
1736 graph: &'g TxGraph<A>,
1737 txids: I,
1738 filter_map: F,
1739 ) -> Self
1740 where
1741 I: IntoIterator<Item = Txid>,
1742 {
1743 Self {
1744 graph,
1745 visited: Default::default(),
1746 queue: txids.into_iter().map(|txid| (0, txid)).collect(),
1747 filter_map,
1748 }
1749 }
1750
1751 #[allow(unused)]
1754 pub(crate) fn from_multiple_exclude_root<I>(
1755 graph: &'g TxGraph<A>,
1756 txids: I,
1757 filter_map: F,
1758 ) -> Self
1759 where
1760 I: IntoIterator<Item = Txid>,
1761 {
1762 let mut descendants = Self {
1763 graph,
1764 visited: Default::default(),
1765 queue: Default::default(),
1766 filter_map,
1767 };
1768 for txid in txids {
1769 descendants.populate_queue(1, txid);
1770 }
1771 descendants
1772 }
1773
1774 pub fn run_until_finished(self) {
1776 self.for_each(|_| {})
1777 }
1778
1779 fn populate_queue(&mut self, depth: usize, txid: Txid) {
1780 let spend_paths = self
1781 .graph
1782 .spends
1783 .range(tx_outpoint_range(txid))
1784 .flat_map(|(_, spends)| spends)
1785 .map(|&txid| (depth, txid));
1786 self.queue.extend(spend_paths);
1787 }
1788}
1789
1790impl<A, F, O> Iterator for TxDescendants<'_, A, F, O>
1791where
1792 F: FnMut(usize, Txid) -> Option<O>,
1793{
1794 type Item = O;
1795
1796 fn next(&mut self) -> Option<Self::Item> {
1797 let (op_spends, txid, item) = loop {
1798 let (op_spends, txid) = self.queue.pop_front()?;
1800 if self.visited.insert(txid) {
1802 if let Some(item) = (self.filter_map)(op_spends, txid) {
1804 break (op_spends, txid, item);
1805 }
1806 }
1807 };
1808
1809 self.populate_queue(op_spends + 1, txid);
1810 Some(item)
1811 }
1812}
1813
1814fn tx_outpoint_range(txid: Txid) -> RangeInclusive<OutPoint> {
1815 OutPoint::new(txid, u32::MIN)..=OutPoint::new(txid, u32::MAX)
1816}