Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
29 changes: 19 additions & 10 deletions crates/chain/src/indexed_tx_graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ use bitcoin::{Block, OutPoint, Transaction, TxOut, Txid};

use crate::{
tx_graph::{self, TxGraph},
Anchor, AnchorFromBlockPosition, BlockId, Indexer, Merge,
Anchor, BlockId, Indexer, Merge, TxPosInBlock,
};

/// The [`IndexedTxGraph`] combines a [`TxGraph`] and an [`Indexer`] implementation.
Expand Down Expand Up @@ -252,17 +252,17 @@ where
}
}

/// Methods are available if the anchor (`A`) implements [`AnchorFromBlockPosition`].
impl<A: Anchor, I: Indexer> IndexedTxGraph<A, I>
/// Methods are available if the anchor (`A`) can be created from [`TxPosInBlock`].
impl<A, I> IndexedTxGraph<A, I>
where
I::ChangeSet: Default + Merge,
A: AnchorFromBlockPosition,
for<'b> A: Anchor + From<TxPosInBlock<'b>>,
I: Indexer,
{
/// Batch insert all transactions of the given `block` of `height`, filtering out those that are
/// irrelevant.
///
/// Each inserted transaction's anchor will be constructed from
/// [`AnchorFromBlockPosition::from_block_position`].
/// Each inserted transaction's anchor will be constructed using [`TxPosInBlock`].
///
/// Relevancy is determined by the internal [`Indexer::is_tx_relevant`] implementation of `I`.
/// Irrelevant transactions in `txs` will be ignored.
Expand All @@ -280,7 +280,12 @@ where
changeset.indexer.merge(self.index.index_tx(tx));
if self.index.is_tx_relevant(tx) {
let txid = tx.compute_txid();
let anchor = A::from_block_position(block, block_id, tx_pos);
let anchor = TxPosInBlock {
block,
block_id,
tx_pos,
}
.into();
changeset.tx_graph.merge(self.graph.insert_tx(tx.clone()));
changeset
.tx_graph
Expand All @@ -292,8 +297,7 @@ where

/// Batch insert all transactions of the given `block` of `height`.
///
/// Each inserted transaction's anchor will be constructed from
/// [`AnchorFromBlockPosition::from_block_position`].
/// Each inserted transaction's anchor will be constructed using [`TxPosInBlock`].
///
/// To only insert relevant transactions, use [`apply_block_relevant`] instead.
///
Expand All @@ -305,7 +309,12 @@ where
};
let mut graph = tx_graph::ChangeSet::default();
for (tx_pos, tx) in block.txdata.iter().enumerate() {
let anchor = A::from_block_position(&block, block_id, tx_pos);
let anchor = TxPosInBlock {
block: &block,
block_id,
tx_pos,
}
.into();
graph.merge(self.graph.insert_anchor(tx.compute_txid(), anchor));
graph.merge(self.graph.insert_tx(tx.clone()));
}
Expand Down
31 changes: 19 additions & 12 deletions crates/chain/src/tx_data_traits.rs
Original file line number Diff line number Diff line change
Expand Up @@ -100,24 +100,31 @@ impl Anchor for ConfirmationBlockTime {
}
}

/// An [`Anchor`] that can be constructed from a given block, block height and transaction position
/// within the block.
pub trait AnchorFromBlockPosition: Anchor {
/// Construct the anchor from a given `block`, block height and `tx_pos` within the block.
fn from_block_position(block: &bitcoin::Block, block_id: BlockId, tx_pos: usize) -> Self;
/// Set of parameters sufficient to construct an [`Anchor`].
///
/// Typically used as an additional constraint on anchor:
/// `for<'b> A: Anchor + From<TxPosInBlock<'b>>`.
Comment thread
jirijakes marked this conversation as resolved.
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub struct TxPosInBlock<'b> {
/// Block in which the transaction appeared.
pub block: &'b bitcoin::Block,
/// Block's [`BlockId`].
pub block_id: BlockId,
/// Position in the block on which the transaction appeared.
pub tx_pos: usize,
}

impl AnchorFromBlockPosition for BlockId {
fn from_block_position(_block: &bitcoin::Block, block_id: BlockId, _tx_pos: usize) -> Self {
block_id
impl<'b> From<TxPosInBlock<'b>> for BlockId {
fn from(pos: TxPosInBlock) -> Self {
pos.block_id
}
}

impl AnchorFromBlockPosition for ConfirmationBlockTime {
fn from_block_position(block: &bitcoin::Block, block_id: BlockId, _tx_pos: usize) -> Self {
impl<'b> From<TxPosInBlock<'b>> for ConfirmationBlockTime {
fn from(pos: TxPosInBlock) -> Self {
Self {
block_id,
confirmation_time: block.header.time as _,
block_id: pos.block_id,
confirmation_time: pos.block.header.time as _,
}
}
}
Expand Down