diff --git a/crates/bitcoind_rpc/tests/test_emitter.rs b/crates/bitcoind_rpc/tests/test_emitter.rs index 8c41efc03..f39006271 100644 --- a/crates/bitcoind_rpc/tests/test_emitter.rs +++ b/crates/bitcoind_rpc/tests/test_emitter.rs @@ -281,7 +281,7 @@ fn process_block( block_height: u32, ) -> anyhow::Result<()> { recv_chain.apply_update(CheckPoint::from_header(&block.header, block_height))?; - let _ = recv_graph.apply_block(block, block_height); + let _ = recv_graph.apply_block(&block, block_height); Ok(()) } diff --git a/crates/chain/src/indexed_tx_graph.rs b/crates/chain/src/indexed_tx_graph.rs index ed2a1f0ce..99431070a 100644 --- a/crates/chain/src/indexed_tx_graph.rs +++ b/crates/chain/src/indexed_tx_graph.rs @@ -7,7 +7,7 @@ use bitcoin::{Block, OutPoint, Transaction, TxOut, Txid}; use crate::{ tx_graph::{self, TxGraph}, - Anchor, AnchorFromBlockPosition, BlockId, Indexer, Merge, + Anchor, BlockId, BlockPosition, Indexer, Merge, }; /// The [`IndexedTxGraph`] combines a [`TxGraph`] and an [`Indexer`] implementation. @@ -252,23 +252,23 @@ where } } -/// Methods are available if the anchor (`A`) implements [`AnchorFromBlockPosition`]. -impl IndexedTxGraph +/// Methods are available if the anchor (`A`) can be created from [`BlockPosition`]. +impl<'b, A, I> IndexedTxGraph where I::ChangeSet: Default + Merge, - A: AnchorFromBlockPosition, + A: Anchor + From>, + 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 [`BlockPosition`]. /// /// Relevancy is determined by the internal [`Indexer::is_tx_relevant`] implementation of `I`. /// Irrelevant transactions in `txs` will be ignored. pub fn apply_block_relevant( - &mut self, - block: &Block, + &'b mut self, + block: &'b Block, height: u32, ) -> ChangeSet { let block_id = BlockId { @@ -276,15 +276,15 @@ where height, }; let mut changeset = ChangeSet::::default(); - for (tx_pos, tx) in block.txdata.iter().enumerate() { + for tx in &block.txdata { 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); changeset.tx_graph.merge(self.graph.insert_tx(tx.clone())); - changeset - .tx_graph - .merge(self.graph.insert_anchor(txid, anchor)); + changeset.tx_graph.merge( + self.graph + .insert_anchor(txid, BlockPosition::new(block, block_id).into()), + ); } } changeset @@ -292,21 +292,22 @@ 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 [`BlockPosition`]. /// /// To only insert relevant transactions, use [`apply_block_relevant`] instead. /// /// [`apply_block_relevant`]: IndexedTxGraph::apply_block_relevant - pub fn apply_block(&mut self, block: Block, height: u32) -> ChangeSet { + pub fn apply_block(&'b mut self, block: &'b Block, height: u32) -> ChangeSet { let block_id = BlockId { hash: block.block_hash(), height, }; 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); - graph.merge(self.graph.insert_anchor(tx.compute_txid(), anchor)); + for tx in &block.txdata { + graph.merge(self.graph.insert_anchor( + tx.compute_txid(), + BlockPosition::new(block, block_id).into(), + )); graph.merge(self.graph.insert_tx(tx.clone())); } let indexer = self.index_tx_graph_changeset(&graph); diff --git a/crates/chain/src/tx_data_traits.rs b/crates/chain/src/tx_data_traits.rs index d3d562bf3..40743e8c5 100644 --- a/crates/chain/src/tx_data_traits.rs +++ b/crates/chain/src/tx_data_traits.rs @@ -100,24 +100,42 @@ 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; +/// Minimal set of parameters that are needed to construct a generic [`Anchor`]. +/// Typically used as an additional constraint on anchor: +/// `A: Anchor + From>`. +pub struct BlockPosition<'b> { + block: &'b bitcoin::Block, + block_id: BlockId, } -impl AnchorFromBlockPosition for BlockId { - fn from_block_position(_block: &bitcoin::Block, block_id: BlockId, _tx_pos: usize) -> Self { - block_id +impl<'b> BlockPosition<'b> { + /// Creates new [`BlockPosition`]. + pub fn new(block: &'b bitcoin::Block, block_id: BlockId) -> Self { + Self { block, block_id } + } + + /// Returns block associated with this [`BlockPosition`]. + pub fn block(&self) -> &bitcoin::Block { + self.block + } + + /// Returns block ID associated with this [`BlockPosition`]. + pub fn block_id(&self) -> BlockId { + self.block_id + } +} + +impl<'b> From> for BlockId { + fn from(value: BlockPosition) -> Self { + value.block_id } } -impl AnchorFromBlockPosition for ConfirmationBlockTime { - fn from_block_position(block: &bitcoin::Block, block_id: BlockId, _tx_pos: usize) -> Self { +impl<'b> From> for ConfirmationBlockTime { + fn from(value: BlockPosition) -> Self { Self { - block_id, - confirmation_time: block.header.time as _, + block_id: value.block_id, + confirmation_time: value.block.header.time as _, } } }