Skip to content

Commit

Permalink
doc: Improve TxGraph & co docs
Browse files Browse the repository at this point in the history
  • Loading branch information
danielabrozzoni committed Nov 3, 2023
1 parent 6ebdd19 commit 1417b49
Show file tree
Hide file tree
Showing 6 changed files with 61 additions and 24 deletions.
4 changes: 4 additions & 0 deletions crates/chain/src/chain_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -147,6 +147,8 @@ impl From<(&u32, &BlockHash)> for BlockId {

/// An [`Anchor`] implementation that also records the exact confirmation height of the transaction.
///
/// Note that the confirmation block and the anchor block can be different here.
///
/// Refer to [`Anchor`] for more details.
#[derive(Debug, Default, Clone, PartialEq, Eq, Copy, PartialOrd, Ord, core::hash::Hash)]
#[cfg_attr(
Expand Down Expand Up @@ -186,6 +188,8 @@ impl AnchorFromBlockPosition for ConfirmationHeightAnchor {
/// An [`Anchor`] implementation that also records the exact confirmation time and height of the
/// transaction.
///
/// Note that the confirmation block and the anchor block can be different here.
///
/// Refer to [`Anchor`] for more details.
#[derive(Debug, Default, Clone, PartialEq, Eq, Copy, PartialOrd, Ord, core::hash::Hash)]
#[cfg_attr(
Expand Down
2 changes: 1 addition & 1 deletion crates/chain/src/chain_oracle.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use crate::BlockId;
/// Represents a service that tracks the blockchain.
///
/// The main method is [`is_block_in_chain`] which determines whether a given block of [`BlockId`]
/// is an ancestor of another "static block".
/// is an ancestor of the `chain_tip`.
///
/// [`is_block_in_chain`]: Self::is_block_in_chain
pub trait ChainOracle {
Expand Down
6 changes: 2 additions & 4 deletions crates/chain/src/indexed_tx_graph.rs
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
//! Contains the [`IndexedTxGraph`] structure and associated types.
//!
//! This is essentially a [`TxGraph`] combined with an indexer.

/// Contains the [`IndexedTxGraph`] structure and associated types. Refer to the
/// [`IndexedTxGraph`] documentation for more.
use alloc::vec::Vec;
use bitcoin::{Block, OutPoint, Transaction, TxOut, Txid};

Expand Down
5 changes: 2 additions & 3 deletions crates/chain/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,8 @@
//! you do it synchronously or asynchronously. If you know a fact about the blockchain, you can just
//! tell `bdk_chain`'s APIs about it, and that information will be integrated, if it can be done
//! consistently.
//! 2. Error-free APIs.
//! 3. Data persistence agnostic -- `bdk_chain` does not care where you cache on-chain data, what you
//! cache or how you fetch it.
//! 2. Data persistence agnostic -- `bdk_chain` does not care where you cache on-chain data, what you
//! cache or how you retrieve it from persistent storage.
//!
//! [Bitcoin Dev Kit]: https://bitcoindevkit.org/

Expand Down
11 changes: 7 additions & 4 deletions crates/chain/src/tx_data_traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,24 @@ use alloc::vec::Vec;

/// Trait that "anchors" blockchain data to a specific block of height and hash.
///
/// [`Anchor`] implementations must be [`Ord`] by the anchor block's [`BlockId`] first.
///
/// I.e. If transaction A is anchored in block B, then if block B is in the best chain, we can
/// If transaction A is anchored in block B, and block B is in the best chain, we can
/// assume that transaction A is also confirmed in the best chain. This does not necessarily mean
/// that transaction A is confirmed in block B. It could also mean transaction A is confirmed in a
/// parent block of B.
///
/// Every [`Anchor`] implementation must contain a [`BlockId`] parameter, and must implement
/// [`Ord`]. When implementing [`Ord`], the anchors' [`BlockId`]s should take precedence
/// over other elements inside the [`Anchor`]s for comparison purposes, i.e., you should first
/// compare the anchors' [`BlockId`]s and then care about the rest.
/// [`BlockId`]s.
///
/// ```
/// # use bdk_chain::local_chain::LocalChain;
/// # use bdk_chain::tx_graph::TxGraph;
/// # use bdk_chain::BlockId;
/// # use bdk_chain::ConfirmationHeightAnchor;
/// # use bdk_chain::example_utils::*;
/// # use bitcoin::hashes::Hash;
///
/// // Initialize the local chain with two blocks.
/// let chain = LocalChain::from_blocks(
/// [
Expand Down
57 changes: 45 additions & 12 deletions crates/chain/src/tx_graph.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,30 @@
//! Module for structures that store and traverse transactions.
//!
//! [`TxGraph`] is a monotone structure that inserts transactions and indexes the spends. The
//! [`ChangeSet`] structure reports changes of [`TxGraph`] but can also be applied to a
//! [`TxGraph`] as well. Lastly, [`TxDescendants`] is an [`Iterator`] that traverses descendants of
//! a given transaction.
//! [`TxGraph`] contains transactions and indexes them so you can easily traverse the graph of those transactions.
//! `TxGraph` is *monotone* in that you can always insert a transaction -- it doesn't care whether that
//! transaction is in the current best chain or whether it conflicts with any of the
//! existing transactions or what order you insert the transactions.
//! Furthermore, there is currently no way to delete a transaction.
//!
//! Transactions can be either whole or partial (i.e., transactions for which we only
//! know some outputs, which we usually call "floating outputs").
//!
//! The graph contains transactions in the form of [`TxNode`]s. Each node contains the
//! txid, the transaction (whole or partial), the blocks it's anchored in (see the [`Anchor`]
//! documentation for more details), and the timestamp of the last time we saw
//! the transaction as unconfirmed.
//!
//! Conflicting transactions are allowed to coexist within a [`TxGraph`]. This is useful for
//! identifying and traversing conflicts and descendants of a given transaction.
//! identifying and traversing conflicts and descendants of a given transaction. Some [`TxGraph`]
//! methods only consider "canonical" (i.e., in the best chain or in mempool) transactions,
//! we decide which transactions are canonical based on anchors `last_seen_unconfirmed`;
//! see the [`try_get_chain_position`] documentation for more details.
//!
//! The [`ChangeSet`] reports changes made to a [`TxGraph`]; it can be used to either save to
//! persistent storage, or to be applied to another [`TxGraph`].
//!
//! Lastly, you can use [`TxAncestors`]/[`TxDescendants`] to traverse ancestors and descendants of
//! a given transaction, respectively.
//!
//! # Applying changes
//!
Expand Down Expand Up @@ -49,6 +67,7 @@
//! let changeset = graph.apply_update(update);
//! assert!(changeset.is_empty());
//! ```
//! [`try_get_chain_position`]: TxGraph::try_get_chain_position

use crate::{
collections::*, keychain::Balance, local_chain::LocalChain, Anchor, Append, BlockId,
Expand Down Expand Up @@ -90,7 +109,7 @@ impl<A> Default for TxGraph<A> {
}
}

/// An outward-facing view of a (transaction) node in the [`TxGraph`].
/// A transaction node in the [`TxGraph`].
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct TxNode<'a, T, A> {
/// Txid of the transaction.
Expand Down Expand Up @@ -127,7 +146,7 @@ impl Default for TxNodeInternal {
}
}

/// An outwards-facing view of a transaction that is part of the *best chain*'s history.
/// A transaction that is included in a certain chain.
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
pub struct CanonicalTx<'a, T, A> {
/// How the transaction is observed as (confirmed or unconfirmed).
Expand Down Expand Up @@ -454,7 +473,7 @@ impl<A: Clone + Ord> TxGraph<A> {
/// Batch insert unconfirmed transactions.
///
/// Items of `txs` are tuples containing the transaction and a *last seen* timestamp. The
/// *last seen* communicates when the transaction is last seen in the mempool which is used for
/// *last seen* communicates when the transaction is last seen in mempool which is used for
/// conflict-resolution (refer to [`TxGraph::insert_seen_at`] for details).
pub fn batch_insert_unconfirmed(
&mut self,
Expand Down Expand Up @@ -687,8 +706,21 @@ impl<A: Anchor> TxGraph<A> {

/// Get the position of the transaction in `chain` with tip `chain_tip`.
///
/// If the given transaction of `txid` does not exist in the chain of `chain_tip`, `None` is
/// returned.
/// If the given `txid` does not exist in the chain of `chain_tip`, and
/// we believe that the transaction is not in mempool anymore, `None` is returned.
///
/// There are two factors that we use to approximate whether an unconfirmed
/// transaction currently exists in mempool:
/// 1. Conflicts with confirmed txs. If the transaction `tx` or any of its unconfirmed
/// ancestors conflict with a confirmed transaction, then `tx` can't be in mempool.
/// 2. The `last_seen_unconfirmed` parameter. Given two conflicting transactions, we say
/// that the one with a higher `last_seen_unconfirmed` (i.e., we saw it later) has a higher
/// chance of still being in mempool. When trying to figure out if `tx`
/// is still in mempool, we first of all calculate `tx`'s `max_last_seen_unconfirmed`,
/// which is the max `last_seen_unconfirmed` between `tx` and all its descendants.
/// We then look at all the conflicts of `tx`, and if for all of them
/// `last_seen_unconfirmed` < `max_last_seen_unconfirmed` holds,
/// then we consider `tx` to be still in mempool.
///
/// # Error
///
Expand All @@ -714,7 +746,7 @@ impl<A: Anchor> TxGraph<A> {
}
}

// The tx is not anchored to a block which is in the best chain, which means that it
// The tx is not anchored to a block in the best chain, which means that it
// might be in mempool, or it might have been dropped already.
// Let's check conflicts to find out!
let tx = match tx_node {
Expand Down Expand Up @@ -911,7 +943,8 @@ impl<A: Anchor> TxGraph<A> {
/// (`OI`) for convenience. If `OI` is not necessary, the caller can use `()`, or
/// [`Iterator::enumerate`] over a list of [`OutPoint`]s.
///
/// Floating outputs are ignored.
/// Floating outputs (i.e., outputs for which we don't have the full transaction in the graph)
/// are ignored.
///
/// # Error
///
Expand Down

0 comments on commit 1417b49

Please sign in to comment.