Skip to content

Commit

Permalink
[bdk_chain_redesign] Add ..in_chain methods
Browse files Browse the repository at this point in the history
Add methods to `TxGraph` and `IndexedTxGraph` that gets in-best-chain
data (such as transactions, txouts, unspent txouts).
  • Loading branch information
evanlinjin committed Mar 27, 2023
1 parent 61a8606 commit 43b648f
Show file tree
Hide file tree
Showing 10 changed files with 236 additions and 64 deletions.
4 changes: 2 additions & 2 deletions crates/bdk/src/wallet/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use bdk_chain::{
chain_graph,
keychain::{persist, KeychainChangeSet, KeychainScan, KeychainTracker},
sparse_chain,
tx_graph::GraphedTx,
tx_graph::TxInGraph,
BlockId, ConfirmationTime,
};
use bitcoin::consensus::encode::serialize;
Expand Down Expand Up @@ -524,7 +524,7 @@ impl<D> Wallet<D> {
/// unconfirmed transactions last.
pub fn transactions(
&self,
) -> impl DoubleEndedIterator<Item = (ConfirmationTime, GraphedTx<'_, Transaction, BlockId>)> + '_
) -> impl DoubleEndedIterator<Item = (ConfirmationTime, TxInGraph<'_, Transaction, BlockId>)> + '_
{
self.keychain_tracker
.chain_graph()
Expand Down
41 changes: 35 additions & 6 deletions crates/chain/src/chain_data.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,41 @@ use crate::{
};

/// Represents an observation of some chain data.
#[derive(Debug, Clone, Copy)]
pub enum Observation<A> {
#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, core::hash::Hash)]
pub enum ObservedIn<A> {
/// The chain data is seen in a block identified by `A`.
InBlock(A),
/// The chain data is seen at this given unix timestamp.
SeenAt(u64),
Block(A),
/// The chain data is seen in mempool at this given timestamp.
Mempool(u64),
}

impl ChainPosition for ObservedIn<BlockId> {
fn height(&self) -> TxHeight {
match self {
ObservedIn::Block(block_id) => TxHeight::Confirmed(block_id.height),
ObservedIn::Mempool(_) => TxHeight::Unconfirmed,
}
}

fn max_ord_of_height(height: TxHeight) -> Self {
match height {
TxHeight::Confirmed(height) => ObservedIn::Block(BlockId {
height,
hash: Hash::from_inner([u8::MAX; 32]),
}),
TxHeight::Unconfirmed => Self::Mempool(u64::MAX),
}
}

fn min_ord_of_height(height: TxHeight) -> Self {
match height {
TxHeight::Confirmed(height) => ObservedIn::Block(BlockId {
height,
hash: Hash::from_inner([u8::MIN; 32]),
}),
TxHeight::Unconfirmed => Self::Mempool(u64::MIN),
}
}
}

/// Represents the height at which a transaction is confirmed.
Expand Down Expand Up @@ -177,7 +206,7 @@ impl From<(&u32, &BlockHash)> for BlockId {
}

/// A `TxOut` with as much data as we can retrieve about it
#[derive(Debug, Clone, PartialEq)]
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct FullTxOut<I> {
/// The location of the `TxOut`.
pub outpoint: OutPoint,
Expand Down
6 changes: 3 additions & 3 deletions crates/chain/src/chain_graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
use crate::{
collections::HashSet,
sparse_chain::{self, ChainPosition, SparseChain},
tx_graph::{self, GraphedTx, TxGraph},
tx_graph::{self, TxGraph, TxInGraph},
BlockAnchor, BlockId, ForEachTxOut, FullTxOut, TxHeight,
};
use alloc::{string::ToString, vec::Vec};
Expand Down Expand Up @@ -213,7 +213,7 @@ where
///
/// This does not necessarily mean that it is *confirmed* in the blockchain; it might just be in
/// the unconfirmed transaction list within the [`SparseChain`].
pub fn get_tx_in_chain(&self, txid: Txid) -> Option<(&P, GraphedTx<'_, Transaction, A>)> {
pub fn get_tx_in_chain(&self, txid: Txid) -> Option<(&P, TxInGraph<'_, Transaction, A>)> {
let position = self.chain.tx_position(txid)?;
let graphed_tx = self.graph.get_tx(txid).expect("must exist");
Some((position, graphed_tx))
Expand Down Expand Up @@ -441,7 +441,7 @@ where
/// in ascending order.
pub fn transactions_in_chain(
&self,
) -> impl DoubleEndedIterator<Item = (&P, GraphedTx<'_, Transaction, A>)> {
) -> impl DoubleEndedIterator<Item = (&P, TxInGraph<'_, Transaction, A>)> {
self.chain
.txids()
.map(move |(pos, txid)| (pos, self.graph.get_tx(*txid).expect("must exist")))
Expand Down
8 changes: 7 additions & 1 deletion crates/chain/src/keychain/txout_index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -88,9 +88,11 @@ impl<K> Deref for KeychainTxOutIndex<K> {
}
}

impl<K: Clone + Ord + Debug> TxIndex for KeychainTxOutIndex<K> {
impl<K: Clone + Ord + Debug + 'static> TxIndex for KeychainTxOutIndex<K> {
type Additions = DerivationAdditions<K>;

type SpkIndex = (K, u32);

fn index_txout(&mut self, outpoint: OutPoint, txout: &TxOut) -> Self::Additions {
self.scan_txout(outpoint, txout)
}
Expand All @@ -102,6 +104,10 @@ impl<K: Clone + Ord + Debug> TxIndex for KeychainTxOutIndex<K> {
fn is_tx_relevant(&self, tx: &bitcoin::Transaction) -> bool {
self.is_relevant(tx)
}

fn relevant_txouts(&self) -> &BTreeMap<OutPoint, (Self::SpkIndex, TxOut)> {
self.inner.relevant_txouts()
}
}

impl<K: Clone + Ord + Debug> KeychainTxOutIndex<K> {
Expand Down
8 changes: 7 additions & 1 deletion crates/chain/src/spk_txout_index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,11 @@ impl<I> Default for SpkTxOutIndex<I> {
}
}

impl<I: Clone + Ord> TxIndex for SpkTxOutIndex<I> {
impl<I: Clone + Ord + 'static> TxIndex for SpkTxOutIndex<I> {
type Additions = BTreeSet<I>;

type SpkIndex = I;

fn index_txout(&mut self, outpoint: OutPoint, txout: &TxOut) -> Self::Additions {
self.scan_txout(outpoint, txout)
.cloned()
Expand All @@ -69,6 +71,10 @@ impl<I: Clone + Ord> TxIndex for SpkTxOutIndex<I> {
fn is_tx_relevant(&self, tx: &Transaction) -> bool {
self.is_relevant(tx)
}

fn relevant_txouts(&self) -> &BTreeMap<OutPoint, (Self::SpkIndex, TxOut)> {
&self.txouts
}
}

/// This macro is used instead of a member function of `SpkTxOutIndex`, which would result in a
Expand Down
7 changes: 6 additions & 1 deletion crates/chain/src/tx_data_traits.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
use alloc::collections::BTreeSet;
use alloc::collections::{BTreeMap, BTreeSet};
use bitcoin::{Block, BlockHash, OutPoint, Transaction, TxOut};

use crate::BlockId;
Expand Down Expand Up @@ -100,6 +100,8 @@ pub trait TxIndex {
/// The resultant "additions" when new transaction data is indexed.
type Additions: TxIndexAdditions;

type SpkIndex: Ord;

/// Scan and index the given `outpoint` and `txout`.
fn index_txout(&mut self, outpoint: OutPoint, txout: &TxOut) -> Self::Additions;

Expand All @@ -120,4 +122,7 @@ pub trait TxIndex {
/// A transaction is relevant if it contains a txout with a script_pubkey that we own, or if it
/// spends an already-indexed outpoint that we have previously indexed.
fn is_tx_relevant(&self, tx: &Transaction) -> bool;

/// Lists all relevant txouts known by the index.
fn relevant_txouts(&self) -> &BTreeMap<OutPoint, (Self::SpkIndex, TxOut)>;
}
Loading

0 comments on commit 43b648f

Please sign in to comment.