[bdk_chain_redesign] Make default anchor for TxGraph
as ()
This allows us to use the old API with minimal changes. `TxGraph` methods have also been rearranged to allow for it.
This commit is contained in:
parent
468701a129
commit
8c906170c9
@ -524,7 +524,7 @@ impl<D> Wallet<D> {
|
|||||||
/// unconfirmed transactions last.
|
/// unconfirmed transactions last.
|
||||||
pub fn transactions(
|
pub fn transactions(
|
||||||
&self,
|
&self,
|
||||||
) -> impl DoubleEndedIterator<Item = (ConfirmationTime, TxInGraph<'_, Transaction, BlockId>)> + '_
|
) -> impl DoubleEndedIterator<Item = (ConfirmationTime, TxInGraph<'_, Transaction, ()>)> + '_
|
||||||
{
|
{
|
||||||
self.keychain_tracker
|
self.keychain_tracker
|
||||||
.chain_graph()
|
.chain_graph()
|
||||||
|
@ -27,7 +27,7 @@ use core::fmt::Debug;
|
|||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct ChainGraph<P = TxHeight> {
|
pub struct ChainGraph<P = TxHeight> {
|
||||||
chain: SparseChain<P>,
|
chain: SparseChain<P>,
|
||||||
graph: TxGraph<BlockId>,
|
graph: TxGraph,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P> Default for ChainGraph<P> {
|
impl<P> Default for ChainGraph<P> {
|
||||||
@ -45,8 +45,8 @@ impl<P> AsRef<SparseChain<P>> for ChainGraph<P> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P> AsRef<TxGraph<BlockId>> for ChainGraph<P> {
|
impl<P> AsRef<TxGraph> for ChainGraph<P> {
|
||||||
fn as_ref(&self) -> &TxGraph<BlockId> {
|
fn as_ref(&self) -> &TxGraph {
|
||||||
&self.graph
|
&self.graph
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -64,7 +64,7 @@ impl<P> ChainGraph<P> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a reference to the internal [`TxGraph`].
|
/// Returns a reference to the internal [`TxGraph`].
|
||||||
pub fn graph(&self) -> &TxGraph<BlockId> {
|
pub fn graph(&self) -> &TxGraph {
|
||||||
&self.graph
|
&self.graph
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -81,7 +81,7 @@ where
|
|||||||
/// transaction in `graph`.
|
/// transaction in `graph`.
|
||||||
/// 2. The `chain` has two transactions that are allegedly in it, but they conflict in the `graph`
|
/// 2. The `chain` has two transactions that are allegedly in it, but they conflict in the `graph`
|
||||||
/// (so could not possibly be in the same chain).
|
/// (so could not possibly be in the same chain).
|
||||||
pub fn new(chain: SparseChain<P>, graph: TxGraph<BlockId>) -> Result<Self, NewError<P>> {
|
pub fn new(chain: SparseChain<P>, graph: TxGraph) -> Result<Self, NewError<P>> {
|
||||||
let mut missing = HashSet::default();
|
let mut missing = HashSet::default();
|
||||||
for (pos, txid) in chain.txids() {
|
for (pos, txid) in chain.txids() {
|
||||||
if let Some(graphed_tx) = graph.get_tx(*txid) {
|
if let Some(graphed_tx) = graph.get_tx(*txid) {
|
||||||
@ -212,7 +212,7 @@ where
|
|||||||
///
|
///
|
||||||
/// This does not necessarily mean that it is *confirmed* in the blockchain; it might just be in
|
/// This does not necessarily mean that it is *confirmed* in the blockchain; it might just be in
|
||||||
/// the unconfirmed transaction list within the [`SparseChain`].
|
/// the unconfirmed transaction list within the [`SparseChain`].
|
||||||
pub fn get_tx_in_chain(&self, txid: Txid) -> Option<(&P, TxInGraph<'_, Transaction, BlockId>)> {
|
pub fn get_tx_in_chain(&self, txid: Txid) -> Option<(&P, TxInGraph<'_, Transaction, ()>)> {
|
||||||
let position = self.chain.tx_position(txid)?;
|
let position = self.chain.tx_position(txid)?;
|
||||||
let graphed_tx = self.graph.get_tx(txid).expect("must exist");
|
let graphed_tx = self.graph.get_tx(txid).expect("must exist");
|
||||||
Some((position, graphed_tx))
|
Some((position, graphed_tx))
|
||||||
@ -430,7 +430,7 @@ where
|
|||||||
/// in ascending order.
|
/// in ascending order.
|
||||||
pub fn transactions_in_chain(
|
pub fn transactions_in_chain(
|
||||||
&self,
|
&self,
|
||||||
) -> impl DoubleEndedIterator<Item = (&P, TxInGraph<'_, Transaction, BlockId>)> {
|
) -> impl DoubleEndedIterator<Item = (&P, TxInGraph<'_, Transaction, ()>)> {
|
||||||
self.chain
|
self.chain
|
||||||
.txids()
|
.txids()
|
||||||
.map(move |(pos, txid)| (pos, self.graph.get_tx(*txid).expect("must exist")))
|
.map(move |(pos, txid)| (pos, self.graph.get_tx(*txid).expect("must exist")))
|
||||||
@ -469,7 +469,7 @@ where
|
|||||||
#[must_use]
|
#[must_use]
|
||||||
pub struct ChangeSet<P> {
|
pub struct ChangeSet<P> {
|
||||||
pub chain: sparse_chain::ChangeSet<P>,
|
pub chain: sparse_chain::ChangeSet<P>,
|
||||||
pub graph: tx_graph::Additions<BlockId>,
|
pub graph: tx_graph::Additions<()>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<P> ChangeSet<P> {
|
impl<P> ChangeSet<P> {
|
||||||
|
@ -55,7 +55,7 @@
|
|||||||
//! assert!(additions.is_empty());
|
//! assert!(additions.is_empty());
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
use crate::{collections::*, BlockAnchor, BlockId, ChainOracle, ForEachTxOut, ObservedIn};
|
use crate::{collections::*, BlockAnchor, ChainOracle, ForEachTxOut, ObservedIn};
|
||||||
use alloc::vec::Vec;
|
use alloc::vec::Vec;
|
||||||
use bitcoin::{OutPoint, Transaction, TxOut, Txid};
|
use bitcoin::{OutPoint, Transaction, TxOut, Txid};
|
||||||
use core::{
|
use core::{
|
||||||
@ -69,7 +69,7 @@ use core::{
|
|||||||
///
|
///
|
||||||
/// [module-level documentation]: crate::tx_graph
|
/// [module-level documentation]: crate::tx_graph
|
||||||
#[derive(Clone, Debug, PartialEq)]
|
#[derive(Clone, Debug, PartialEq)]
|
||||||
pub struct TxGraph<A = BlockId> {
|
pub struct TxGraph<A = ()> {
|
||||||
// all transactions that the graph is aware of in format: `(tx_node, tx_anchors, tx_last_seen)`
|
// all transactions that the graph is aware of in format: `(tx_node, tx_anchors, tx_last_seen)`
|
||||||
txs: HashMap<Txid, (TxNode, BTreeSet<A>, u64)>,
|
txs: HashMap<Txid, (TxNode, BTreeSet<A>, u64)>,
|
||||||
spends: BTreeMap<OutPoint, HashSet<Txid>>,
|
spends: BTreeMap<OutPoint, HashSet<Txid>>,
|
||||||
@ -244,9 +244,111 @@ impl<A> TxGraph<A> {
|
|||||||
|
|
||||||
Some(inputs_sum - outputs_sum)
|
Some(inputs_sum - outputs_sum)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// The transactions spending from this output.
|
||||||
|
///
|
||||||
|
/// `TxGraph` allows conflicting transactions within the graph. Obviously the transactions in
|
||||||
|
/// the returned set will never be in the same active-chain.
|
||||||
|
pub fn outspends(&self, outpoint: OutPoint) -> &HashSet<Txid> {
|
||||||
|
self.spends.get(&outpoint).unwrap_or(&self.empty_outspends)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Iterates over the transactions spending from `txid`.
|
||||||
|
///
|
||||||
|
/// The iterator item is a union of `(vout, txid-set)` where:
|
||||||
|
///
|
||||||
|
/// - `vout` is the provided `txid`'s outpoint that is being spent
|
||||||
|
/// - `txid-set` is the set of txids spending the `vout`.
|
||||||
|
pub fn tx_outspends(
|
||||||
|
&self,
|
||||||
|
txid: Txid,
|
||||||
|
) -> impl DoubleEndedIterator<Item = (u32, &HashSet<Txid>)> + '_ {
|
||||||
|
let start = OutPoint { txid, vout: 0 };
|
||||||
|
let end = OutPoint {
|
||||||
|
txid,
|
||||||
|
vout: u32::MAX,
|
||||||
|
};
|
||||||
|
self.spends
|
||||||
|
.range(start..=end)
|
||||||
|
.map(|(outpoint, spends)| (outpoint.vout, spends))
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Iterate over all partial transactions (outputs only) in the graph.
|
||||||
|
pub fn partial_transactions(
|
||||||
|
&self,
|
||||||
|
) -> impl Iterator<Item = TxInGraph<'_, BTreeMap<u32, TxOut>, A>> {
|
||||||
|
self.txs
|
||||||
|
.iter()
|
||||||
|
.filter_map(|(&txid, (tx, anchors, last_seen))| match tx {
|
||||||
|
TxNode::Whole(_) => None,
|
||||||
|
TxNode::Partial(partial) => Some(TxInGraph {
|
||||||
|
txid,
|
||||||
|
tx: partial,
|
||||||
|
anchors,
|
||||||
|
last_seen: *last_seen,
|
||||||
|
}),
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates an iterator that filters and maps descendants from the starting `txid`.
|
||||||
|
///
|
||||||
|
/// The supplied closure takes in two inputs `(depth, descendant_txid)`:
|
||||||
|
///
|
||||||
|
/// * `depth` is the distance between the starting `txid` and the `descendant_txid`. I.e., if the
|
||||||
|
/// descendant is spending an output of the starting `txid`; the `depth` will be 1.
|
||||||
|
/// * `descendant_txid` is the descendant's txid which we are considering to walk.
|
||||||
|
///
|
||||||
|
/// The supplied closure returns an `Option<T>`, allowing the caller to map each node it vists
|
||||||
|
/// and decide whether to visit descendants.
|
||||||
|
pub fn walk_descendants<'g, F, O>(&'g self, txid: Txid, walk_map: F) -> TxDescendants<A, F>
|
||||||
|
where
|
||||||
|
F: FnMut(usize, Txid) -> Option<O> + 'g,
|
||||||
|
{
|
||||||
|
TxDescendants::new_exclude_root(self, txid, walk_map)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Creates an iterator that both filters and maps conflicting transactions (this includes
|
||||||
|
/// descendants of directly-conflicting transactions, which are also considered conflicts).
|
||||||
|
///
|
||||||
|
/// Refer to [`Self::walk_descendants`] for `walk_map` usage.
|
||||||
|
pub fn walk_conflicts<'g, F, O>(
|
||||||
|
&'g self,
|
||||||
|
tx: &'g Transaction,
|
||||||
|
walk_map: F,
|
||||||
|
) -> TxDescendants<A, F>
|
||||||
|
where
|
||||||
|
F: FnMut(usize, Txid) -> Option<O> + 'g,
|
||||||
|
{
|
||||||
|
let txids = self.direct_conflicts_of_tx(tx).map(|(_, txid)| txid);
|
||||||
|
TxDescendants::from_multiple_include_root(self, txids, walk_map)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Given a transaction, return an iterator of txids that directly conflict with the given
|
||||||
|
/// transaction's inputs (spends). The conflicting txids are returned with the given
|
||||||
|
/// transaction's vin (in which it conflicts).
|
||||||
|
///
|
||||||
|
/// Note that this only returns directly conflicting txids and does not include descendants of
|
||||||
|
/// those txids (which are technically also conflicting).
|
||||||
|
pub fn direct_conflicts_of_tx<'g>(
|
||||||
|
&'g self,
|
||||||
|
tx: &'g Transaction,
|
||||||
|
) -> impl Iterator<Item = (usize, Txid)> + '_ {
|
||||||
|
let txid = tx.txid();
|
||||||
|
tx.input
|
||||||
|
.iter()
|
||||||
|
.enumerate()
|
||||||
|
.filter_map(move |(vin, txin)| self.spends.get(&txin.previous_output).zip(Some(vin)))
|
||||||
|
.flat_map(|(spends, vin)| core::iter::repeat(vin).zip(spends.iter().cloned()))
|
||||||
|
.filter(move |(_, conflicting_txid)| *conflicting_txid != txid)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Whether the graph has any transactions or outputs in it.
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
self.txs.is_empty()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A: BlockAnchor> TxGraph<A> {
|
impl<A: Clone + Ord> TxGraph<A> {
|
||||||
/// Construct a new [`TxGraph`] from a list of transactions.
|
/// Construct a new [`TxGraph`] from a list of transactions.
|
||||||
pub fn new(txs: impl IntoIterator<Item = Transaction>) -> Self {
|
pub fn new(txs: impl IntoIterator<Item = Transaction>) -> Self {
|
||||||
let mut new = Self::default();
|
let mut new = Self::default();
|
||||||
@ -256,6 +358,24 @@ impl<A: BlockAnchor> TxGraph<A> {
|
|||||||
new
|
new
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the resultant [`Additions`] if the given `txout` is inserted at `outpoint`. Does not
|
||||||
|
/// mutate `self`.
|
||||||
|
///
|
||||||
|
/// The [`Additions`] result will be empty if the `outpoint` (or a full transaction containing
|
||||||
|
/// the `outpoint`) already existed in `self`.
|
||||||
|
pub fn insert_txout_preview(&self, outpoint: OutPoint, txout: TxOut) -> Additions<A> {
|
||||||
|
let mut update = Self::default();
|
||||||
|
update.txs.insert(
|
||||||
|
outpoint.txid,
|
||||||
|
(
|
||||||
|
TxNode::Partial([(outpoint.vout, txout)].into()),
|
||||||
|
BTreeSet::new(),
|
||||||
|
0,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
self.determine_additions(&update)
|
||||||
|
}
|
||||||
|
|
||||||
/// Inserts the given [`TxOut`] at [`OutPoint`].
|
/// Inserts the given [`TxOut`] at [`OutPoint`].
|
||||||
///
|
///
|
||||||
/// Note this will ignore the action if we already have the full transaction that the txout is
|
/// Note this will ignore the action if we already have the full transaction that the txout is
|
||||||
@ -266,6 +386,18 @@ impl<A: BlockAnchor> TxGraph<A> {
|
|||||||
additions
|
additions
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the resultant [`Additions`] if the given transaction is inserted. Does not actually
|
||||||
|
/// mutate [`Self`].
|
||||||
|
///
|
||||||
|
/// The [`Additions`] result will be empty if `tx` already exists in `self`.
|
||||||
|
pub fn insert_tx_preview(&self, tx: Transaction) -> Additions<A> {
|
||||||
|
let mut update = Self::default();
|
||||||
|
update
|
||||||
|
.txs
|
||||||
|
.insert(tx.txid(), (TxNode::Whole(tx), BTreeSet::new(), 0));
|
||||||
|
self.determine_additions(&update)
|
||||||
|
}
|
||||||
|
|
||||||
/// Inserts the given transaction into [`TxGraph`].
|
/// Inserts the given transaction into [`TxGraph`].
|
||||||
///
|
///
|
||||||
/// The [`Additions`] returned will be empty if `tx` already exists.
|
/// The [`Additions`] returned will be empty if `tx` already exists.
|
||||||
@ -275,6 +407,13 @@ impl<A: BlockAnchor> TxGraph<A> {
|
|||||||
additions
|
additions
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the resultant [`Additions`] if the `txid` is set in `anchor`.
|
||||||
|
pub fn insert_anchor_preview(&self, txid: Txid, anchor: A) -> Additions<A> {
|
||||||
|
let mut update = Self::default();
|
||||||
|
update.anchors.insert((anchor, txid));
|
||||||
|
self.determine_additions(&update)
|
||||||
|
}
|
||||||
|
|
||||||
/// Inserts the given `anchor` into [`TxGraph`].
|
/// Inserts the given `anchor` into [`TxGraph`].
|
||||||
///
|
///
|
||||||
/// This is equivalent to calling [`insert_anchor_preview`] and [`apply_additions`] in sequence.
|
/// This is equivalent to calling [`insert_anchor_preview`] and [`apply_additions`] in sequence.
|
||||||
@ -289,6 +428,16 @@ impl<A: BlockAnchor> TxGraph<A> {
|
|||||||
additions
|
additions
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Returns the resultant [`Additions`] if the `txid` is set to `seen_at`.
|
||||||
|
///
|
||||||
|
/// Note that [`TxGraph`] only keeps track of the lastest `seen_at`.
|
||||||
|
pub fn insert_seen_at_preview(&self, txid: Txid, seen_at: u64) -> Additions<A> {
|
||||||
|
let mut update = Self::default();
|
||||||
|
let (_, _, update_last_seen) = update.txs.entry(txid).or_default();
|
||||||
|
*update_last_seen = seen_at;
|
||||||
|
self.determine_additions(&update)
|
||||||
|
}
|
||||||
|
|
||||||
/// Inserts the given `seen_at` into [`TxGraph`].
|
/// Inserts the given `seen_at` into [`TxGraph`].
|
||||||
///
|
///
|
||||||
/// This is equivalent to calling [`insert_seen_at_preview`] and [`apply_additions`] in
|
/// This is equivalent to calling [`insert_seen_at_preview`] and [`apply_additions`] in
|
||||||
@ -421,54 +570,9 @@ impl<A: BlockAnchor> TxGraph<A> {
|
|||||||
|
|
||||||
additions
|
additions
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns the resultant [`Additions`] if the given transaction is inserted. Does not actually
|
impl<A: BlockAnchor> TxGraph<A> {
|
||||||
/// mutate [`Self`].
|
|
||||||
///
|
|
||||||
/// The [`Additions`] result will be empty if `tx` already exists in `self`.
|
|
||||||
pub fn insert_tx_preview(&self, tx: Transaction) -> Additions<A> {
|
|
||||||
let mut update = Self::default();
|
|
||||||
update
|
|
||||||
.txs
|
|
||||||
.insert(tx.txid(), (TxNode::Whole(tx), BTreeSet::new(), 0));
|
|
||||||
self.determine_additions(&update)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the resultant [`Additions`] if the given `txout` is inserted at `outpoint`. Does not
|
|
||||||
/// mutate `self`.
|
|
||||||
///
|
|
||||||
/// The [`Additions`] result will be empty if the `outpoint` (or a full transaction containing
|
|
||||||
/// the `outpoint`) already existed in `self`.
|
|
||||||
pub fn insert_txout_preview(&self, outpoint: OutPoint, txout: TxOut) -> Additions<A> {
|
|
||||||
let mut update = Self::default();
|
|
||||||
update.txs.insert(
|
|
||||||
outpoint.txid,
|
|
||||||
(
|
|
||||||
TxNode::Partial([(outpoint.vout, txout)].into()),
|
|
||||||
BTreeSet::new(),
|
|
||||||
0,
|
|
||||||
),
|
|
||||||
);
|
|
||||||
self.determine_additions(&update)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the resultant [`Additions`] if the `txid` is set in `anchor`.
|
|
||||||
pub fn insert_anchor_preview(&self, txid: Txid, anchor: A) -> Additions<A> {
|
|
||||||
let mut update = Self::default();
|
|
||||||
update.anchors.insert((anchor, txid));
|
|
||||||
self.determine_additions(&update)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the resultant [`Additions`] if the `txid` is set to `seen_at`.
|
|
||||||
///
|
|
||||||
/// Note that [`TxGraph`] only keeps track of the lastest `seen_at`.
|
|
||||||
pub fn insert_seen_at_preview(&self, txid: Txid, seen_at: u64) -> Additions<A> {
|
|
||||||
let mut update = Self::default();
|
|
||||||
let (_, _, update_last_seen) = update.txs.entry(txid).or_default();
|
|
||||||
*update_last_seen = seen_at;
|
|
||||||
self.determine_additions(&update)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Get all heights that are relevant to the graph.
|
/// Get all heights that are relevant to the graph.
|
||||||
pub fn relevant_heights(&self) -> BTreeSet<u32> {
|
pub fn relevant_heights(&self) -> BTreeSet<u32> {
|
||||||
self.anchors
|
self.anchors
|
||||||
@ -573,110 +677,6 @@ impl<A: BlockAnchor> TxGraph<A> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<A> TxGraph<A> {
|
|
||||||
/// The transactions spending from this output.
|
|
||||||
///
|
|
||||||
/// `TxGraph` allows conflicting transactions within the graph. Obviously the transactions in
|
|
||||||
/// the returned set will never be in the same active-chain.
|
|
||||||
pub fn outspends(&self, outpoint: OutPoint) -> &HashSet<Txid> {
|
|
||||||
self.spends.get(&outpoint).unwrap_or(&self.empty_outspends)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Iterates over the transactions spending from `txid`.
|
|
||||||
///
|
|
||||||
/// The iterator item is a union of `(vout, txid-set)` where:
|
|
||||||
///
|
|
||||||
/// - `vout` is the provided `txid`'s outpoint that is being spent
|
|
||||||
/// - `txid-set` is the set of txids spending the `vout`.
|
|
||||||
pub fn tx_outspends(
|
|
||||||
&self,
|
|
||||||
txid: Txid,
|
|
||||||
) -> impl DoubleEndedIterator<Item = (u32, &HashSet<Txid>)> + '_ {
|
|
||||||
let start = OutPoint { txid, vout: 0 };
|
|
||||||
let end = OutPoint {
|
|
||||||
txid,
|
|
||||||
vout: u32::MAX,
|
|
||||||
};
|
|
||||||
self.spends
|
|
||||||
.range(start..=end)
|
|
||||||
.map(|(outpoint, spends)| (outpoint.vout, spends))
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Iterate over all partial transactions (outputs only) in the graph.
|
|
||||||
pub fn partial_transactions(
|
|
||||||
&self,
|
|
||||||
) -> impl Iterator<Item = TxInGraph<'_, BTreeMap<u32, TxOut>, A>> {
|
|
||||||
self.txs
|
|
||||||
.iter()
|
|
||||||
.filter_map(|(&txid, (tx, anchors, last_seen))| match tx {
|
|
||||||
TxNode::Whole(_) => None,
|
|
||||||
TxNode::Partial(partial) => Some(TxInGraph {
|
|
||||||
txid,
|
|
||||||
tx: partial,
|
|
||||||
anchors,
|
|
||||||
last_seen: *last_seen,
|
|
||||||
}),
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates an iterator that filters and maps descendants from the starting `txid`.
|
|
||||||
///
|
|
||||||
/// The supplied closure takes in two inputs `(depth, descendant_txid)`:
|
|
||||||
///
|
|
||||||
/// * `depth` is the distance between the starting `txid` and the `descendant_txid`. I.e., if the
|
|
||||||
/// descendant is spending an output of the starting `txid`; the `depth` will be 1.
|
|
||||||
/// * `descendant_txid` is the descendant's txid which we are considering to walk.
|
|
||||||
///
|
|
||||||
/// The supplied closure returns an `Option<T>`, allowing the caller to map each node it vists
|
|
||||||
/// and decide whether to visit descendants.
|
|
||||||
pub fn walk_descendants<'g, F, O>(&'g self, txid: Txid, walk_map: F) -> TxDescendants<A, F>
|
|
||||||
where
|
|
||||||
F: FnMut(usize, Txid) -> Option<O> + 'g,
|
|
||||||
{
|
|
||||||
TxDescendants::new_exclude_root(self, txid, walk_map)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Creates an iterator that both filters and maps conflicting transactions (this includes
|
|
||||||
/// descendants of directly-conflicting transactions, which are also considered conflicts).
|
|
||||||
///
|
|
||||||
/// Refer to [`Self::walk_descendants`] for `walk_map` usage.
|
|
||||||
pub fn walk_conflicts<'g, F, O>(
|
|
||||||
&'g self,
|
|
||||||
tx: &'g Transaction,
|
|
||||||
walk_map: F,
|
|
||||||
) -> TxDescendants<A, F>
|
|
||||||
where
|
|
||||||
F: FnMut(usize, Txid) -> Option<O> + 'g,
|
|
||||||
{
|
|
||||||
let txids = self.direct_conflicts_of_tx(tx).map(|(_, txid)| txid);
|
|
||||||
TxDescendants::from_multiple_include_root(self, txids, walk_map)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Given a transaction, return an iterator of txids that directly conflict with the given
|
|
||||||
/// transaction's inputs (spends). The conflicting txids are returned with the given
|
|
||||||
/// transaction's vin (in which it conflicts).
|
|
||||||
///
|
|
||||||
/// Note that this only returns directly conflicting txids and does not include descendants of
|
|
||||||
/// those txids (which are technically also conflicting).
|
|
||||||
pub fn direct_conflicts_of_tx<'g>(
|
|
||||||
&'g self,
|
|
||||||
tx: &'g Transaction,
|
|
||||||
) -> impl Iterator<Item = (usize, Txid)> + '_ {
|
|
||||||
let txid = tx.txid();
|
|
||||||
tx.input
|
|
||||||
.iter()
|
|
||||||
.enumerate()
|
|
||||||
.filter_map(move |(vin, txin)| self.spends.get(&txin.previous_output).zip(Some(vin)))
|
|
||||||
.flat_map(|(spends, vin)| core::iter::repeat(vin).zip(spends.iter().cloned()))
|
|
||||||
.filter(move |(_, conflicting_txid)| *conflicting_txid != txid)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Whether the graph has any transactions or outputs in it.
|
|
||||||
pub fn is_empty(&self) -> bool {
|
|
||||||
self.txs.is_empty()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A structure that represents changes to a [`TxGraph`].
|
/// A structure that represents changes to a [`TxGraph`].
|
||||||
///
|
///
|
||||||
/// It is named "additions" because [`TxGraph`] is monotone, so transactions can only be added and
|
/// It is named "additions" because [`TxGraph`] is monotone, so transactions can only be added and
|
||||||
@ -698,7 +698,7 @@ impl<A> TxGraph<A> {
|
|||||||
)
|
)
|
||||||
)]
|
)]
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub struct Additions<A = BlockId> {
|
pub struct Additions<A> {
|
||||||
pub tx: BTreeSet<Transaction>,
|
pub tx: BTreeSet<Transaction>,
|
||||||
pub txout: BTreeMap<OutPoint, TxOut>,
|
pub txout: BTreeMap<OutPoint, TxOut>,
|
||||||
pub anchors: BTreeSet<(A, Txid)>,
|
pub anchors: BTreeSet<(A, Txid)>,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user