mempool: snapshot 5 + query: new tools + server: endpoints

This commit is contained in:
nym21
2025-12-14 02:06:14 +01:00
parent db5d784ff7
commit b491b1f41f
79 changed files with 1588 additions and 129 deletions
+46 -3
View File
@@ -3,11 +3,12 @@ use std::collections::BTreeMap;
use brk_computer::Computer;
use brk_error::Result;
use brk_indexer::Indexer;
use brk_monitor::Mempool;
use brk_mempool::Mempool;
use brk_reader::Reader;
use brk_types::{
Address, AddressStats, BlockInfo, BlockStatus, Height, Index, IndexInfo, Limit, MempoolInfo,
Metric, MetricCount, RecommendedFees, Transaction, TreeNode, TxStatus, Txid, TxidPath, Utxo,
Address, AddressStats, BlockInfo, BlockStatus, BlockTimestamp, DifficultyAdjustment, Height,
Index, IndexInfo, Limit, MempoolBlock, MempoolInfo, Metric, MetricCount, RecommendedFees,
Timestamp, Transaction, TreeNode, TxOutspend, TxStatus, Txid, TxidPath, Utxo, Vout,
};
use tokio::task::spawn_blocking;
@@ -57,6 +58,11 @@ impl AsyncQuery {
spawn_blocking(move || query.get_address_utxos(address)).await?
}
pub async fn get_address_mempool_txids(&self, address: Address) -> Result<Vec<Txid>> {
let query = self.0.clone();
spawn_blocking(move || query.get_address_mempool_txids(address)).await?
}
pub async fn get_transaction(&self, txid: TxidPath) -> Result<Transaction> {
let query = self.0.clone();
spawn_blocking(move || query.get_transaction(txid)).await?
@@ -72,6 +78,16 @@ impl AsyncQuery {
spawn_blocking(move || query.get_transaction_hex(txid)).await?
}
pub async fn get_tx_outspend(&self, txid: TxidPath, vout: Vout) -> Result<TxOutspend> {
let query = self.0.clone();
spawn_blocking(move || query.get_tx_outspend(txid, vout)).await?
}
pub async fn get_tx_outspends(&self, txid: TxidPath) -> Result<Vec<TxOutspend>> {
let query = self.0.clone();
spawn_blocking(move || query.get_tx_outspends(txid)).await?
}
pub async fn get_block(&self, hash: String) -> Result<BlockInfo> {
let query = self.0.clone();
spawn_blocking(move || query.get_block(&hash)).await?
@@ -82,6 +98,10 @@ impl AsyncQuery {
spawn_blocking(move || query.get_block_by_height(height)).await?
}
pub async fn get_block_by_timestamp(&self, timestamp: Timestamp) -> Result<BlockTimestamp> {
self.0.get_block_by_timestamp(timestamp)
}
pub async fn get_block_status(&self, hash: String) -> Result<BlockStatus> {
let query = self.0.clone();
spawn_blocking(move || query.get_block_status(&hash)).await?
@@ -97,6 +117,20 @@ impl AsyncQuery {
spawn_blocking(move || query.get_block_txids(&hash)).await?
}
pub async fn get_block_txs(&self, hash: String, start_index: usize) -> Result<Vec<Transaction>> {
let query = self.0.clone();
spawn_blocking(move || query.get_block_txs(&hash, start_index)).await?
}
pub async fn get_block_txid_at_index(&self, hash: String, index: usize) -> Result<Txid> {
self.0.get_block_txid_at_index(&hash, index)
}
pub async fn get_block_raw(&self, hash: String) -> Result<Vec<u8>> {
let query = self.0.clone();
spawn_blocking(move || query.get_block_raw(&hash)).await?
}
pub async fn get_mempool_info(&self) -> Result<MempoolInfo> {
self.0.get_mempool_info()
}
@@ -109,6 +143,15 @@ impl AsyncQuery {
self.0.get_recommended_fees()
}
pub async fn get_mempool_blocks(&self) -> Result<Vec<MempoolBlock>> {
self.0.get_mempool_blocks()
}
pub async fn get_difficulty_adjustment(&self) -> Result<DifficultyAdjustment> {
let query = self.0.clone();
spawn_blocking(move || query.get_difficulty_adjustment()).await?
}
pub async fn match_metric(&self, metric: Metric, limit: Limit) -> Result<Vec<&'static str>> {
let query = self.0.clone();
spawn_blocking(move || Ok(query.match_metric(&metric, limit))).await?
@@ -0,0 +1,24 @@
use std::str::FromStr;
use brk_error::{Error, Result};
use brk_types::{Address, AddressBytes, Txid};
use crate::Query;
/// Maximum number of mempool txids to return
const MAX_MEMPOOL_TXIDS: usize = 50;
/// Get mempool transaction IDs for an address
pub fn get_address_mempool_txids(address: Address, query: &Query) -> Result<Vec<Txid>> {
let mempool = query.mempool().ok_or(Error::Str("Mempool not available"))?;
let bytes = AddressBytes::from_str(&address.address)?;
let addresses = mempool.get_addresses();
let txids: Vec<Txid> = addresses
.get(&bytes)
.map(|(_, txids)| txids.iter().take(MAX_MEMPOOL_TXIDS).cloned().collect())
.unwrap_or_default();
Ok(txids)
}
+4
View File
@@ -1,8 +1,12 @@
mod addr;
mod mempool_txids;
mod resolve;
mod txids;
mod utxos;
mod validate;
pub use addr::*;
pub use mempool_txids::*;
pub use txids::*;
pub use utxos::*;
pub use validate::*;
@@ -0,0 +1,41 @@
use bitcoin::hex::DisplayHex;
use brk_types::{AddressBytes, AddressValidation, OutputType};
/// Validate a Bitcoin address and return details
pub fn validate_address(address: &str) -> AddressValidation {
let Ok(script) = AddressBytes::address_to_script(address) else {
return AddressValidation::invalid();
};
let output_type = OutputType::from(&script);
let script_hex = script.as_bytes().to_lower_hex_string();
let is_script = matches!(output_type, OutputType::P2SH);
let is_witness = matches!(
output_type,
OutputType::P2WPKH | OutputType::P2WSH | OutputType::P2TR | OutputType::P2A
);
let (witness_version, witness_program) = if is_witness {
let version = script.witness_version().map(|v| v.to_num());
// Witness program is after the version byte and push opcode
let program = if script.len() > 2 {
Some(script.as_bytes()[2..].to_lower_hex_string())
} else {
None
};
(version, program)
} else {
(None, None)
};
AddressValidation {
isvalid: true,
address: Some(address.to_string()),
script_pub_key: Some(script_hex),
isscript: Some(is_script),
iswitness: Some(is_witness),
witness_version,
witness_program,
}
}
@@ -0,0 +1,75 @@
use brk_error::{Error, Result};
use brk_types::{BlockTimestamp, Date, DateIndex, Height, Timestamp};
use jiff::Timestamp as JiffTimestamp;
use vecdb::{AnyVec, GenericStoredVec, TypedVecIterator};
use crate::Query;
/// Get the block closest to a given timestamp using dateindex for fast lookup
pub fn get_block_by_timestamp(timestamp: Timestamp, query: &Query) -> Result<BlockTimestamp> {
let indexer = query.indexer();
let computer = query.computer();
let max_height = query.get_height();
let max_height_usize: usize = max_height.into();
if max_height_usize == 0 {
return Err(Error::Str("No blocks indexed"));
}
let target = timestamp;
let date = Date::from(target);
let dateindex = DateIndex::try_from(date).unwrap_or_default();
// Get first height of the target date
let first_height_of_day = computer
.indexes
.dateindex_to_first_height
.read_once(dateindex)
.unwrap_or(Height::from(0usize));
let start: usize = usize::from(first_height_of_day).min(max_height_usize);
// Use iterator for efficient sequential access
let mut timestamp_iter = indexer.vecs.block.height_to_timestamp.iter()?;
// Search forward from start to find the last block <= target timestamp
let mut best_height = start;
let mut best_ts = timestamp_iter.get_unwrap(Height::from(start));
for h in (start + 1)..=max_height_usize {
let height = Height::from(h);
let block_ts = timestamp_iter.get_unwrap(height);
if block_ts <= target {
best_height = h;
best_ts = block_ts;
} else {
break;
}
}
// Check one block before start in case we need to go backward
if start > 0 && best_ts > target {
let prev_height = Height::from(start - 1);
let prev_ts = timestamp_iter.get_unwrap(prev_height);
if prev_ts <= target {
best_height = start - 1;
best_ts = prev_ts;
}
}
let height = Height::from(best_height);
let blockhash = indexer.vecs.block.height_to_blockhash.iter()?.get_unwrap(height);
// Convert timestamp to ISO 8601 format
let ts_secs: i64 = (*best_ts).into();
let iso_timestamp = JiffTimestamp::from_second(ts_secs)
.map(|t| t.to_string())
.unwrap_or_else(|_| best_ts.to_string());
Ok(BlockTimestamp {
height,
hash: blockhash,
timestamp: iso_timestamp,
})
}
+8
View File
@@ -1,11 +1,19 @@
mod by_timestamp;
mod height_by_hash;
mod info;
mod list;
mod raw;
mod status;
mod txid_at_index;
mod txids;
mod txs;
pub use by_timestamp::*;
pub use height_by_hash::*;
pub use info::*;
pub use list::*;
pub use raw::*;
pub use status::*;
pub use txid_at_index::*;
pub use txids::*;
pub use txs::*;
+29
View File
@@ -0,0 +1,29 @@
use brk_error::{Error, Result};
use brk_types::Height;
use vecdb::{AnyVec, GenericStoredVec};
use crate::Query;
/// Get raw block bytes by height
pub fn get_block_raw(height: Height, query: &Query) -> Result<Vec<u8>> {
let indexer = query.indexer();
let computer = query.computer();
let reader = query.reader();
let max_height = Height::from(
indexer
.vecs
.block
.height_to_blockhash
.len()
.saturating_sub(1),
);
if height > max_height {
return Err(Error::Str("Block height out of range"));
}
let position = computer.blks.height_to_position.read_once(height)?;
let size = indexer.vecs.block.height_to_total_size.read_once(height)?;
reader.read_raw_bytes(position, *size as usize)
}
@@ -0,0 +1,36 @@
use brk_error::{Error, Result};
use brk_types::{Height, TxIndex, Txid};
use vecdb::{AnyVec, GenericStoredVec, TypedVecIterator};
use crate::Query;
/// Get a single txid at a specific index within a block
pub fn get_block_txid_at_index(height: Height, index: usize, query: &Query) -> Result<Txid> {
let indexer = query.indexer();
let max_height = query.get_height();
if height > max_height {
return Err(Error::Str("Block height out of range"));
}
let first_txindex = indexer.vecs.tx.height_to_first_txindex.read_once(height)?;
let next_first_txindex = indexer
.vecs
.tx
.height_to_first_txindex
.read_once(height.incremented())
.unwrap_or_else(|_| TxIndex::from(indexer.vecs.tx.txindex_to_txid.len()));
let first: usize = first_txindex.into();
let next: usize = next_first_txindex.into();
let tx_count = next - first;
if index >= tx_count {
return Err(Error::Str("Transaction index out of range"));
}
let txindex = TxIndex::from(first + index);
let txid = indexer.vecs.tx.txindex_to_txid.iter()?.get_unwrap(txindex);
Ok(txid)
}
+45
View File
@@ -0,0 +1,45 @@
use brk_error::{Error, Result};
use brk_types::{Height, Transaction, TxIndex};
use vecdb::{AnyVec, GenericStoredVec};
use crate::{Query, chain::tx::get_transaction_by_index};
pub const BLOCK_TXS_PAGE_SIZE: usize = 25;
/// Get paginated transactions in a block by height
pub fn get_block_txs(height: Height, start_index: usize, query: &Query) -> Result<Vec<Transaction>> {
let indexer = query.indexer();
let max_height = query.get_height();
if height > max_height {
return Err(Error::Str("Block height out of range"));
}
let first_txindex = indexer.vecs.tx.height_to_first_txindex.read_once(height)?;
let next_first_txindex = indexer
.vecs
.tx
.height_to_first_txindex
.read_once(height.incremented())
.unwrap_or_else(|_| TxIndex::from(indexer.vecs.tx.txindex_to_txid.len()));
let first: usize = first_txindex.into();
let next: usize = next_first_txindex.into();
let tx_count = next - first;
if start_index >= tx_count {
return Ok(Vec::new());
}
let end_index = (start_index + BLOCK_TXS_PAGE_SIZE).min(tx_count);
let count = end_index - start_index;
let mut txs = Vec::with_capacity(count);
for i in start_index..end_index {
let txindex = TxIndex::from(first + i);
let tx = get_transaction_by_index(txindex, query)?;
txs.push(tx);
}
Ok(txs)
}
@@ -0,0 +1,20 @@
use brk_error::{Error, Result};
use brk_types::MempoolBlock;
use crate::Query;
/// Get projected mempool blocks for fee estimation
pub fn get_mempool_blocks(query: &Query) -> Result<Vec<MempoolBlock>> {
let mempool = query.mempool().ok_or(Error::Str("Mempool not available"))?;
let block_stats = mempool.get_block_stats();
let blocks = block_stats
.into_iter()
.map(|stats| {
MempoolBlock::new(stats.tx_count, stats.total_vsize, stats.total_fee, stats.fee_range)
})
.collect();
Ok(blocks)
}
@@ -1,7 +1,9 @@
mod blocks;
mod fees;
mod info;
mod txids;
pub use blocks::*;
pub use fees::*;
pub use info::*;
pub use txids::*;
@@ -0,0 +1,120 @@
use std::time::{SystemTime, UNIX_EPOCH};
use brk_error::Result;
use brk_types::{DifficultyAdjustment, DifficultyEpoch, Height};
use vecdb::GenericStoredVec;
use crate::Query;
/// Blocks per difficulty epoch (2 weeks target)
const BLOCKS_PER_EPOCH: u32 = 2016;
/// Target block time in seconds (10 minutes)
const TARGET_BLOCK_TIME: u64 = 600;
/// Get difficulty adjustment information
pub fn get_difficulty_adjustment(query: &Query) -> Result<DifficultyAdjustment> {
let indexer = query.indexer();
let computer = query.computer();
let current_height = query.get_height();
let current_height_u32: u32 = current_height.into();
// Get current epoch
let current_epoch = computer
.indexes
.height_to_difficultyepoch
.read_once(current_height)?;
let current_epoch_usize: usize = current_epoch.into();
// Get epoch start height
let epoch_start_height = computer
.indexes
.difficultyepoch_to_first_height
.read_once(current_epoch)?;
let epoch_start_u32: u32 = epoch_start_height.into();
// Calculate epoch progress
let next_retarget_height = epoch_start_u32 + BLOCKS_PER_EPOCH;
let blocks_into_epoch = current_height_u32 - epoch_start_u32;
let remaining_blocks = next_retarget_height - current_height_u32;
let progress_percent = (blocks_into_epoch as f64 / BLOCKS_PER_EPOCH as f64) * 100.0;
// Get timestamps using difficultyepoch_to_timestamp for epoch start
let epoch_start_timestamp = computer
.chain
.difficultyepoch_to_timestamp
.read_once(current_epoch)?;
let current_timestamp = indexer
.vecs
.block
.height_to_timestamp
.read_once(current_height)?;
// Calculate average block time in current epoch
let elapsed_time = (*current_timestamp - *epoch_start_timestamp) as u64;
let time_avg = if blocks_into_epoch > 0 {
elapsed_time / blocks_into_epoch as u64
} else {
TARGET_BLOCK_TIME
};
// Estimate remaining time and retarget date
let remaining_time = remaining_blocks as u64 * time_avg;
let now = SystemTime::now()
.duration_since(UNIX_EPOCH)
.map(|d| d.as_secs())
.unwrap_or(*current_timestamp as u64);
let estimated_retarget_date = now + remaining_time;
// Calculate expected vs actual time for difficulty change estimate
let expected_time = blocks_into_epoch as u64 * TARGET_BLOCK_TIME;
let difficulty_change = if elapsed_time > 0 && blocks_into_epoch > 0 {
((expected_time as f64 / elapsed_time as f64) - 1.0) * 100.0
} else {
0.0
};
// Time offset from expected schedule
let time_offset = expected_time as i64 - elapsed_time as i64;
// Calculate previous retarget using stored difficulty values
let previous_retarget = if current_epoch_usize > 0 {
let prev_epoch = DifficultyEpoch::from(current_epoch_usize - 1);
let prev_epoch_start = computer
.indexes
.difficultyepoch_to_first_height
.read_once(prev_epoch)?;
let prev_difficulty = indexer
.vecs
.block
.height_to_difficulty
.read_once(prev_epoch_start)?;
let curr_difficulty = indexer
.vecs
.block
.height_to_difficulty
.read_once(epoch_start_height)?;
if *prev_difficulty > 0.0 {
((*curr_difficulty / *prev_difficulty) - 1.0) * 100.0
} else {
0.0
}
} else {
0.0
};
Ok(DifficultyAdjustment {
progress_percent,
difficulty_change,
estimated_retarget_date,
remaining_blocks,
remaining_time,
previous_retarget,
next_retarget_height: Height::from(next_retarget_height),
time_avg,
adjusted_time_avg: time_avg,
time_offset,
})
}
+3
View File
@@ -0,0 +1,3 @@
mod difficulty;
pub use difficulty::*;
+2
View File
@@ -1,9 +1,11 @@
mod addr;
mod block;
mod mempool;
mod mining;
mod tx;
pub use addr::*;
pub use block::*;
pub use mempool::*;
pub use mining::*;
pub use tx::*;
+2
View File
@@ -1,7 +1,9 @@
mod hex;
mod outspend;
mod status;
mod tx;
pub use hex::*;
pub use outspend::*;
pub use status::*;
pub use tx::*;
+160
View File
@@ -0,0 +1,160 @@
use std::str::FromStr;
use brk_error::{Error, Result};
use brk_types::{TxInIndex, TxOutspend, TxStatus, Txid, TxidPath, TxidPrefix, Vin, Vout};
use vecdb::{GenericStoredVec, TypedVecIterator};
use crate::Query;
/// Get the spend status of a specific output
pub fn get_tx_outspend(
TxidPath { txid }: TxidPath,
vout: Vout,
query: &Query,
) -> Result<TxOutspend> {
let Ok(txid) = bitcoin::Txid::from_str(&txid) else {
return Err(Error::InvalidTxid);
};
let txid = Txid::from(txid);
// Mempool outputs are unspent in on-chain terms
if let Some(mempool) = query.mempool()
&& mempool.get_txs().contains_key(&txid)
{
return Ok(TxOutspend::UNSPENT);
}
// Look up confirmed transaction
let prefix = TxidPrefix::from(&txid);
let indexer = query.indexer();
let Ok(Some(txindex)) = indexer
.stores
.txidprefix_to_txindex
.get(&prefix)
.map(|opt| opt.map(|cow| cow.into_owned()))
else {
return Err(Error::UnknownTxid);
};
// Calculate txoutindex
let first_txoutindex = indexer
.vecs
.tx
.txindex_to_first_txoutindex
.read_once(txindex)?;
let txoutindex = first_txoutindex + vout;
// Look up spend status
let computer = query.computer();
let txinindex = computer.stateful.txoutindex_to_txinindex.read_once(txoutindex)?;
if txinindex == TxInIndex::UNSPENT {
return Ok(TxOutspend::UNSPENT);
}
get_outspend_details(txinindex, query)
}
/// Get the spend status of all outputs in a transaction
pub fn get_tx_outspends(TxidPath { txid }: TxidPath, query: &Query) -> Result<Vec<TxOutspend>> {
let Ok(txid) = bitcoin::Txid::from_str(&txid) else {
return Err(Error::InvalidTxid);
};
let txid = Txid::from(txid);
// Mempool outputs are unspent in on-chain terms
if let Some(mempool) = query.mempool()
&& let Some(tx_with_hex) = mempool.get_txs().get(&txid)
{
let output_count = tx_with_hex.tx().output.len();
return Ok(vec![TxOutspend::UNSPENT; output_count]);
}
// Look up confirmed transaction
let prefix = TxidPrefix::from(&txid);
let indexer = query.indexer();
let Ok(Some(txindex)) = indexer
.stores
.txidprefix_to_txindex
.get(&prefix)
.map(|opt| opt.map(|cow| cow.into_owned()))
else {
return Err(Error::UnknownTxid);
};
// Get output range
let first_txoutindex = indexer
.vecs
.tx
.txindex_to_first_txoutindex
.read_once(txindex)?;
let next_first_txoutindex = indexer
.vecs
.tx
.txindex_to_first_txoutindex
.read_once(txindex.incremented())?;
let output_count = usize::from(next_first_txoutindex) - usize::from(first_txoutindex);
// Get spend status for each output
let computer = query.computer();
let mut txoutindex_to_txinindex_iter = computer.stateful.txoutindex_to_txinindex.iter()?;
let mut outspends = Vec::with_capacity(output_count);
for i in 0..output_count {
let txoutindex = first_txoutindex + Vout::from(i);
let txinindex = txoutindex_to_txinindex_iter.get_unwrap(txoutindex);
if txinindex == TxInIndex::UNSPENT {
outspends.push(TxOutspend::UNSPENT);
} else {
outspends.push(get_outspend_details(txinindex, query)?);
}
}
Ok(outspends)
}
/// Get spending transaction details from a txinindex
fn get_outspend_details(txinindex: TxInIndex, query: &Query) -> Result<TxOutspend> {
let indexer = query.indexer();
let computer = query.computer();
// Look up spending txindex directly
let spending_txindex = computer.indexes.txinindex_to_txindex.read_once(txinindex)?;
// Calculate vin
let spending_first_txinindex = indexer
.vecs
.tx
.txindex_to_first_txinindex
.read_once(spending_txindex)?;
let vin = Vin::from(usize::from(txinindex) - usize::from(spending_first_txinindex));
// Get spending tx details
let spending_txid = indexer.vecs.tx.txindex_to_txid.read_once(spending_txindex)?;
let spending_height = indexer.vecs.tx.txindex_to_height.read_once(spending_txindex)?;
let block_hash = indexer
.vecs
.block
.height_to_blockhash
.read_once(spending_height)?;
let block_time = indexer
.vecs
.block
.height_to_timestamp
.read_once(spending_height)?;
Ok(TxOutspend {
spent: true,
txid: Some(spending_txid),
vin: Some(vin),
status: Some(TxStatus {
confirmed: true,
block_height: Some(spending_height),
block_hash: Some(block_hash),
block_time: Some(block_time),
}),
})
}
+51 -7
View File
@@ -6,12 +6,13 @@ use std::{collections::BTreeMap, sync::Arc};
use brk_computer::Computer;
use brk_error::{Error, Result};
use brk_indexer::Indexer;
use brk_monitor::Mempool;
use brk_mempool::Mempool;
use brk_reader::Reader;
use brk_traversable::TreeNode;
use brk_types::{
Address, AddressStats, BlockInfo, BlockStatus, Format, Height, Index, IndexInfo, Limit,
MempoolInfo, Metric, MetricCount, RecommendedFees, Transaction, TxStatus, Txid, TxidPath, Utxo,
Address, AddressStats, BlockInfo, BlockStatus, BlockTimestamp, Format, Height, Index,
IndexInfo, Limit, MempoolInfo, Metric, MetricCount, RecommendedFees, Timestamp, Transaction,
TxOutspend, TxStatus, Txid, TxidPath, Utxo, Vout,
};
use vecdb::{AnyExportableVec, AnyStoredVec};
@@ -31,12 +32,16 @@ pub use pagination::{PaginatedIndexParam, PaginatedMetrics, PaginationParam};
pub use params::{Params, ParamsDeprec, ParamsOpt};
use vecs::Vecs;
pub use crate::chain::BLOCK_TXS_PAGE_SIZE;
pub use crate::chain::validate_address;
use crate::{
chain::{
get_address, get_address_txids, get_address_utxos, get_block_by_height,
get_block_status_by_height, get_block_txids, get_blocks, get_height_by_hash,
get_mempool_info, get_mempool_txids, get_recommended_fees, get_transaction,
get_transaction_hex, get_transaction_status,
get_address, get_address_mempool_txids, get_address_txids, get_address_utxos,
get_block_by_height, get_block_by_timestamp, get_block_raw, get_block_status_by_height,
get_block_txid_at_index, get_block_txids, get_block_txs, get_blocks,
get_difficulty_adjustment, get_height_by_hash, get_mempool_blocks, get_mempool_info,
get_mempool_txids, get_recommended_fees, get_transaction, get_transaction_hex,
get_transaction_status, get_tx_outspend, get_tx_outspends,
},
vecs::{IndexToVec, MetricToVec},
};
@@ -93,6 +98,10 @@ impl Query {
get_address_utxos(address, self)
}
pub fn get_address_mempool_txids(&self, address: Address) -> Result<Vec<Txid>> {
get_address_mempool_txids(address, self)
}
pub fn get_transaction(&self, txid: TxidPath) -> Result<Transaction> {
get_transaction(txid, self)
}
@@ -105,6 +114,14 @@ impl Query {
get_transaction_hex(txid, self)
}
pub fn get_tx_outspend(&self, txid: TxidPath, vout: Vout) -> Result<TxOutspend> {
get_tx_outspend(txid, vout, self)
}
pub fn get_tx_outspends(&self, txid: TxidPath) -> Result<Vec<TxOutspend>> {
get_tx_outspends(txid, self)
}
pub fn get_block(&self, hash: &str) -> Result<BlockInfo> {
let height = get_height_by_hash(hash, self)?;
get_block_by_height(height, self)
@@ -114,6 +131,10 @@ impl Query {
get_block_by_height(height, self)
}
pub fn get_block_by_timestamp(&self, timestamp: Timestamp) -> Result<BlockTimestamp> {
get_block_by_timestamp(timestamp, self)
}
pub fn get_block_status(&self, hash: &str) -> Result<BlockStatus> {
let height = get_height_by_hash(hash, self)?;
get_block_status_by_height(height, self)
@@ -128,6 +149,21 @@ impl Query {
get_block_txids(height, self)
}
pub fn get_block_txs(&self, hash: &str, start_index: usize) -> Result<Vec<Transaction>> {
let height = get_height_by_hash(hash, self)?;
get_block_txs(height, start_index, self)
}
pub fn get_block_txid_at_index(&self, hash: &str, index: usize) -> Result<Txid> {
let height = get_height_by_hash(hash, self)?;
get_block_txid_at_index(height, index, self)
}
pub fn get_block_raw(&self, hash: &str) -> Result<Vec<u8>> {
let height = get_height_by_hash(hash, self)?;
get_block_raw(height, self)
}
pub fn get_mempool_info(&self) -> Result<MempoolInfo> {
get_mempool_info(self)
}
@@ -140,6 +176,14 @@ impl Query {
get_recommended_fees(self)
}
pub fn get_mempool_blocks(&self) -> Result<Vec<brk_types::MempoolBlock>> {
get_mempool_blocks(self)
}
pub fn get_difficulty_adjustment(&self) -> Result<brk_types::DifficultyAdjustment> {
get_difficulty_adjustment(self)
}
pub fn match_metric(&self, metric: &Metric, limit: Limit) -> Vec<&'static str> {
self.vecs().matches(metric, limit)
}