Skip to main content

brk_query/impl/block/
txs.rs

1use brk_error::{Error, Result};
2use brk_types::{BlockHash, Height, Transaction, TxIndex, Txid};
3use vecdb::{AnyVec, GenericStoredVec, TypedVecIterator};
4
5use super::BLOCK_TXS_PAGE_SIZE;
6use crate::Query;
7
8impl Query {
9    pub fn block_txids(&self, hash: &BlockHash) -> Result<Vec<Txid>> {
10        let height = self.height_by_hash(hash)?;
11        self.block_txids_by_height(height)
12    }
13
14    pub fn block_txs(&self, hash: &BlockHash, start_index: TxIndex) -> Result<Vec<Transaction>> {
15        let height = self.height_by_hash(hash)?;
16        self.block_txs_by_height(height, start_index.into())
17    }
18
19    pub fn block_txid_at_index(&self, hash: &BlockHash, index: TxIndex) -> Result<Txid> {
20        let height = self.height_by_hash(hash)?;
21        self.block_txid_at_index_by_height(height, index.into())
22    }
23
24    // === Helper methods ===
25
26    fn block_txids_by_height(&self, height: Height) -> Result<Vec<Txid>> {
27        let indexer = self.indexer();
28
29        let max_height = self.height();
30        if height > max_height {
31            return Err(Error::OutOfRange("Block height out of range".into()));
32        }
33
34        let first_txindex = indexer.vecs.transactions.first_txindex.read_once(height)?;
35        let next_first_txindex = indexer
36            .vecs
37            .transactions
38            .first_txindex
39            .read_once(height.incremented())
40            .unwrap_or_else(|_| TxIndex::from(indexer.vecs.transactions.txid.len()));
41
42        let first: usize = first_txindex.into();
43        let next: usize = next_first_txindex.into();
44        let count = next - first;
45
46        let txids: Vec<Txid> = indexer
47            .vecs
48            .transactions
49            .txid
50            .iter()?
51            .skip(first)
52            .take(count)
53            .collect();
54
55        Ok(txids)
56    }
57
58    fn block_txs_by_height(
59        &self,
60        height: Height,
61        start_index: usize,
62    ) -> Result<Vec<Transaction>> {
63        let indexer = self.indexer();
64
65        let max_height = self.height();
66        if height > max_height {
67            return Err(Error::OutOfRange("Block height out of range".into()));
68        }
69
70        let first_txindex = indexer.vecs.transactions.first_txindex.read_once(height)?;
71        let next_first_txindex = indexer
72            .vecs
73            .transactions
74            .first_txindex
75            .read_once(height.incremented())
76            .unwrap_or_else(|_| TxIndex::from(indexer.vecs.transactions.txid.len()));
77
78        let first: usize = first_txindex.into();
79        let next: usize = next_first_txindex.into();
80        let tx_count = next - first;
81
82        if start_index >= tx_count {
83            return Ok(Vec::new());
84        }
85
86        let end_index = (start_index + BLOCK_TXS_PAGE_SIZE).min(tx_count);
87        let count = end_index - start_index;
88
89        let mut txs = Vec::with_capacity(count);
90        for i in start_index..end_index {
91            let txindex = TxIndex::from(first + i);
92            let tx = self.transaction_by_index(txindex)?;
93            txs.push(tx);
94        }
95
96        Ok(txs)
97    }
98
99    fn block_txid_at_index_by_height(&self, height: Height, index: usize) -> Result<Txid> {
100        let indexer = self.indexer();
101
102        let max_height = self.height();
103        if height > max_height {
104            return Err(Error::OutOfRange("Block height out of range".into()));
105        }
106
107        let first_txindex = indexer.vecs.transactions.first_txindex.read_once(height)?;
108        let next_first_txindex = indexer
109            .vecs
110            .transactions
111            .first_txindex
112            .read_once(height.incremented())
113            .unwrap_or_else(|_| TxIndex::from(indexer.vecs.transactions.txid.len()));
114
115        let first: usize = first_txindex.into();
116        let next: usize = next_first_txindex.into();
117        let tx_count = next - first;
118
119        if index >= tx_count {
120            return Err(Error::OutOfRange("Transaction index out of range".into()));
121        }
122
123        let txindex = TxIndex::from(first + index);
124        let txid = indexer.vecs.transactions.txid.iter()?.get_unwrap(txindex);
125
126        Ok(txid)
127    }
128}