global: snapshot

This commit is contained in:
nym21
2025-12-13 10:52:00 +01:00
parent 3526a177fc
commit 158b0254ed
73 changed files with 2230 additions and 195 deletions
+63 -3
View File
@@ -6,13 +6,13 @@ use brk_indexer::Indexer;
use brk_monitor::Mempool;
use brk_reader::Reader;
use brk_types::{
Address, AddressStats, Height, Index, IndexInfo, Limit, Metric, MetricCount, Transaction,
TreeNode, TxidPath,
Address, AddressStats, BlockInfo, BlockStatus, Height, Index, IndexInfo, Limit, MempoolInfo,
Metric, MetricCount, Transaction, TreeNode, TxStatus, Txid, TxidPath, Utxo,
};
use tokio::task::spawn_blocking;
use crate::{
Output, PaginatedIndexParam, PaginatedMetrics, PaginationParam, Params, ParamsOpt, Query,
Output, PaginatedIndexParam, PaginatedMetrics, PaginationParam, Params, Query,
vecs::{IndexToVec, MetricToVec, Vecs},
};
@@ -42,11 +42,71 @@ impl AsyncQuery {
spawn_blocking(move || query.get_address(address)).await?
}
pub async fn get_address_txids(
&self,
address: Address,
after_txid: Option<Txid>,
limit: usize,
) -> Result<Vec<Txid>> {
let query = self.0.clone();
spawn_blocking(move || query.get_address_txids(address, after_txid, limit)).await?
}
pub async fn get_address_utxos(&self, address: Address) -> Result<Vec<Utxo>> {
let query = self.0.clone();
spawn_blocking(move || query.get_address_utxos(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?
}
pub async fn get_transaction_status(&self, txid: TxidPath) -> Result<TxStatus> {
let query = self.0.clone();
spawn_blocking(move || query.get_transaction_status(txid)).await?
}
pub async fn get_transaction_hex(&self, txid: TxidPath) -> Result<String> {
let query = self.0.clone();
spawn_blocking(move || query.get_transaction_hex(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?
}
pub async fn get_block_by_height(&self, height: Height) -> Result<BlockInfo> {
let query = self.0.clone();
spawn_blocking(move || query.get_block_by_height(height)).await?
}
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?
}
pub async fn get_blocks(&self, start_height: Option<Height>) -> Result<Vec<BlockInfo>> {
let query = self.0.clone();
spawn_blocking(move || query.get_blocks(start_height)).await?
}
pub async fn get_block_txids(&self, hash: String) -> Result<Vec<Txid>> {
let query = self.0.clone();
spawn_blocking(move || query.get_block_txids(&hash)).await?
}
pub async fn get_mempool_info(&self) -> Result<MempoolInfo> {
let query = self.0.clone();
spawn_blocking(move || query.get_mempool_info()).await?
}
pub async fn get_mempool_txids(&self) -> Result<Vec<Txid>> {
let query = self.0.clone();
spawn_blocking(move || query.get_mempool_txids()).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?
+8
View File
@@ -0,0 +1,8 @@
mod addr;
mod resolve;
mod txids;
mod utxos;
pub use addr::*;
pub use txids::*;
pub use utxos::*;
@@ -0,0 +1,27 @@
use std::str::FromStr;
use brk_error::{Error, Result};
use brk_types::{Address, AddressBytes, AddressHash, OutputType, TypeIndex};
use crate::Query;
/// Resolve an address string to its output type and type_index
pub fn resolve_address(address: &Address, query: &Query) -> Result<(OutputType, TypeIndex)> {
let stores = &query.indexer().stores;
let bytes = AddressBytes::from_str(&address.address)?;
let outputtype = OutputType::from(&bytes);
let hash = AddressHash::from(&bytes);
let Ok(Some(type_index)) = stores
.addresstype_to_addresshash_to_addressindex
.get(outputtype)
.unwrap()
.get(&hash)
.map(|opt| opt.map(|cow| cow.into_owned()))
else {
return Err(Error::UnknownAddress);
};
Ok((outputtype, type_index))
}
+60
View File
@@ -0,0 +1,60 @@
use brk_error::{Error, Result};
use brk_types::{Address, AddressIndexTxIndex, TxIndex, Txid, Unit};
use vecdb::TypedVecIterator;
use super::resolve::resolve_address;
use crate::Query;
/// Get transaction IDs for an address, newest first
pub fn get_address_txids(
address: Address,
after_txid: Option<Txid>,
limit: usize,
query: &Query,
) -> Result<Vec<Txid>> {
let indexer = query.indexer();
let stores = &indexer.stores;
let (outputtype, type_index) = resolve_address(&address, query)?;
let store = stores
.addresstype_to_addressindex_and_txindex
.get(outputtype)
.unwrap();
let prefix = u32::from(type_index).to_be_bytes();
let after_txindex = if let Some(after_txid) = after_txid {
let txindex = stores
.txidprefix_to_txindex
.get(&after_txid.into())
.map_err(|_| Error::Str("Failed to look up after_txid"))?
.ok_or(Error::Str("after_txid not found"))?
.into_owned();
Some(txindex)
} else {
None
};
let txindices: Vec<TxIndex> = store
.prefix(prefix)
.rev()
.filter(|(key, _): &(AddressIndexTxIndex, Unit)| {
if let Some(after) = after_txindex {
TxIndex::from(key.txindex()) < after
} else {
true
}
})
.take(limit)
.map(|(key, _)| TxIndex::from(key.txindex()))
.collect();
let mut txindex_to_txid_iter = indexer.vecs.tx.txindex_to_txid.iter()?;
let txids: Vec<Txid> = txindices
.into_iter()
.map(|txindex| txindex_to_txid_iter.get_unwrap(txindex))
.collect();
Ok(txids)
}
+65
View File
@@ -0,0 +1,65 @@
use brk_error::Result;
use brk_types::{
Address, AddressIndexOutPoint, Sats, TxIndex, TxStatus, Txid, Unit, Utxo, Vout,
};
use vecdb::TypedVecIterator;
use super::resolve::resolve_address;
use crate::Query;
/// Get UTXOs for an address
pub fn get_address_utxos(address: Address, query: &Query) -> Result<Vec<Utxo>> {
let indexer = query.indexer();
let stores = &indexer.stores;
let vecs = &indexer.vecs;
let (outputtype, type_index) = resolve_address(&address, query)?;
let store = stores
.addresstype_to_addressindex_and_unspentoutpoint
.get(outputtype)
.unwrap();
let prefix = u32::from(type_index).to_be_bytes();
// Collect outpoints (txindex, vout)
let outpoints: Vec<(TxIndex, Vout)> = store
.prefix(prefix)
.map(|(key, _): (AddressIndexOutPoint, Unit)| (key.txindex(), key.vout()))
.collect();
// Create iterators for looking up tx data
let mut txindex_to_txid_iter = vecs.tx.txindex_to_txid.iter()?;
let mut txindex_to_height_iter = vecs.tx.txindex_to_height.iter()?;
let mut txindex_to_first_txoutindex_iter = vecs.tx.txindex_to_first_txoutindex.iter()?;
let mut txoutindex_to_value_iter = vecs.txout.txoutindex_to_value.iter()?;
let mut height_to_blockhash_iter = vecs.block.height_to_blockhash.iter()?;
let mut height_to_timestamp_iter = vecs.block.height_to_timestamp.iter()?;
let utxos: Vec<Utxo> = outpoints
.into_iter()
.map(|(txindex, vout)| {
let txid: Txid = txindex_to_txid_iter.get_unwrap(txindex);
let height = txindex_to_height_iter.get_unwrap(txindex);
let first_txoutindex = txindex_to_first_txoutindex_iter.get_unwrap(txindex);
let txoutindex = first_txoutindex + vout;
let value: Sats = txoutindex_to_value_iter.get_unwrap(txoutindex);
let block_hash = height_to_blockhash_iter.get_unwrap(height);
let block_time = height_to_timestamp_iter.get_unwrap(height);
Utxo {
txid,
vout,
status: TxStatus {
confirmed: true,
block_height: Some(height),
block_hash: Some(block_hash),
block_time: Some(block_time),
},
value,
}
})
.collect();
Ok(utxos)
}
@@ -0,0 +1,19 @@
use brk_error::{Error, Result};
use brk_types::{BlockHash, BlockHashPrefix, Height};
use crate::Query;
/// Resolve a block hash to height
pub fn get_height_by_hash(hash: &str, query: &Query) -> Result<Height> {
let indexer = query.indexer();
let blockhash: BlockHash = hash.parse().map_err(|_| Error::Str("Invalid block hash"))?;
let prefix = BlockHashPrefix::from(&blockhash);
indexer
.stores
.blockhashprefix_to_height
.get(&prefix)?
.map(|h| *h)
.ok_or(Error::Str("Block not found"))
}
+62
View File
@@ -0,0 +1,62 @@
use brk_error::{Error, Result};
use brk_types::{BlockInfo, Height, TxIndex};
use vecdb::{AnyVec, GenericStoredVec, VecIndex};
use crate::Query;
/// Get block info by height
pub fn get_block_by_height(height: Height, query: &Query) -> Result<BlockInfo> {
let indexer = query.indexer();
let max_height = max_height(query);
if height > max_height {
return Err(Error::Str("Block height out of range"));
}
let blockhash = indexer.vecs.block.height_to_blockhash.read_once(height)?;
let difficulty = indexer.vecs.block.height_to_difficulty.read_once(height)?;
let timestamp = indexer.vecs.block.height_to_timestamp.read_once(height)?;
let size = indexer.vecs.block.height_to_total_size.read_once(height)?;
let weight = indexer.vecs.block.height_to_weight.read_once(height)?;
let tx_count = tx_count_at_height(height, max_height, query)?;
Ok(BlockInfo {
id: blockhash,
height,
tx_count,
size: *size,
weight,
timestamp,
difficulty: *difficulty,
})
}
fn max_height(query: &Query) -> Height {
Height::from(
query
.indexer()
.vecs
.block
.height_to_blockhash
.len()
.saturating_sub(1),
)
}
fn tx_count_at_height(height: Height, max_height: Height, query: &Query) -> Result<u32> {
let indexer = query.indexer();
let computer = query.computer();
let first_txindex = indexer.vecs.tx.height_to_first_txindex.read_once(height)?;
let next_first_txindex = if height < max_height {
indexer
.vecs
.tx
.height_to_first_txindex
.read_once(height.incremented())?
} else {
TxIndex::from(computer.indexes.txindex_to_txindex.len())
};
Ok((next_first_txindex.to_usize() - first_txindex.to_usize()) as u32)
}
+27
View File
@@ -0,0 +1,27 @@
use brk_error::Result;
use brk_types::{BlockInfo, Height};
use crate::Query;
use super::info::get_block_by_height;
const DEFAULT_BLOCK_COUNT: u32 = 10;
/// Get a list of blocks, optionally starting from a specific height
pub fn get_blocks(start_height: Option<Height>, query: &Query) -> Result<Vec<BlockInfo>> {
let max_height = query.get_height();
let start = start_height.unwrap_or(max_height);
let start = start.min(max_height);
let start_u32: u32 = start.into();
let count = DEFAULT_BLOCK_COUNT.min(start_u32 + 1);
let mut blocks = Vec::with_capacity(count as usize);
for i in 0..count {
let height = Height::from(start_u32 - i);
blocks.push(get_block_by_height(height, query)?);
}
Ok(blocks)
}
+11
View File
@@ -0,0 +1,11 @@
mod height_by_hash;
mod info;
mod list;
mod status;
mod txids;
pub use height_by_hash::*;
pub use info::*;
pub use list::*;
pub use status::*;
pub use txids::*;
@@ -0,0 +1,37 @@
use brk_error::Result;
use brk_types::{BlockStatus, Height};
use vecdb::{AnyVec, GenericStoredVec};
use crate::Query;
/// Get block status by height
pub fn get_block_status_by_height(height: Height, query: &Query) -> Result<BlockStatus> {
let indexer = query.indexer();
let max_height = Height::from(
indexer
.vecs
.block
.height_to_blockhash
.len()
.saturating_sub(1),
);
if height > max_height {
return Ok(BlockStatus::not_in_best_chain());
}
let next_best = if height < max_height {
Some(
indexer
.vecs
.block
.height_to_blockhash
.read_once(height.incremented())?,
)
} else {
None
};
Ok(BlockStatus::in_best_chain(height, next_best))
}
+38
View File
@@ -0,0 +1,38 @@
use brk_error::{Error, Result};
use brk_types::{Height, TxIndex, Txid};
use vecdb::{AnyVec, GenericStoredVec};
use crate::Query;
/// Get all txids in a block by height
pub fn get_block_txids(height: Height, query: &Query) -> Result<Vec<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 count = next - first;
let txids: Vec<Txid> = indexer
.vecs
.tx
.txindex_to_txid
.iter()?
.skip(first)
.take(count)
.collect();
Ok(txids)
}
@@ -0,0 +1,10 @@
use brk_error::{Error, Result};
use brk_types::MempoolInfo;
use crate::Query;
/// Get mempool statistics
pub fn get_mempool_info(query: &Query) -> Result<MempoolInfo> {
let mempool = query.mempool().ok_or(Error::Str("Mempool not available"))?;
Ok(mempool.get_info())
}
@@ -0,0 +1,5 @@
mod info;
mod txids;
pub use info::*;
pub use txids::*;
@@ -0,0 +1,11 @@
use brk_error::{Error, Result};
use brk_types::Txid;
use crate::Query;
/// Get all mempool transaction IDs
pub fn get_mempool_txids(query: &Query) -> Result<Vec<Txid>> {
let mempool = query.mempool().ok_or(Error::Str("Mempool not available"))?;
let txs = mempool.get_txs();
Ok(txs.keys().cloned().collect())
}
+8 -4
View File
@@ -1,5 +1,9 @@
mod addresses;
mod transactions;
mod addr;
mod block;
mod mempool;
mod tx;
pub use addresses::*;
pub use transactions::*;
pub use addr::*;
pub use block::*;
pub use mempool::*;
pub use tx::*;
+50
View File
@@ -0,0 +1,50 @@
use std::str::FromStr;
use bitcoin::hex::DisplayHex;
use brk_error::{Error, Result};
use brk_types::{TxIndex, Txid, TxidPath, TxidPrefix};
use vecdb::GenericStoredVec;
use crate::Query;
pub fn get_transaction_hex(TxidPath { txid }: TxidPath, query: &Query) -> Result<String> {
let Ok(txid) = bitcoin::Txid::from_str(&txid) else {
return Err(Error::InvalidTxid);
};
let txid = Txid::from(txid);
// First check mempool for unconfirmed transactions
if let Some(mempool) = query.mempool()
&& let Some(tx_with_hex) = mempool.get_txs().get(&txid)
{
return Ok(tx_with_hex.hex().to_string());
}
// Look up confirmed transaction by txid prefix
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_transaction_hex_by_index(txindex, query)
}
pub fn get_transaction_hex_by_index(txindex: TxIndex, query: &Query) -> Result<String> {
let indexer = query.indexer();
let reader = query.reader();
let computer = query.computer();
let total_size = indexer.vecs.tx.txindex_to_total_size.read_once(txindex)?;
let position = computer.blks.txindex_to_position.read_once(txindex)?;
let buffer = reader.read_raw_bytes(position, *total_size as usize)?;
Ok(buffer.to_lower_hex_string())
}
+7
View File
@@ -0,0 +1,7 @@
mod hex;
mod status;
mod tx;
pub use hex::*;
pub use status::*;
pub use tx::*;
+46
View File
@@ -0,0 +1,46 @@
use std::str::FromStr;
use brk_error::{Error, Result};
use brk_types::{TxStatus, Txid, TxidPath, TxidPrefix};
use vecdb::GenericStoredVec;
use crate::Query;
pub fn get_transaction_status(TxidPath { txid }: TxidPath, query: &Query) -> Result<TxStatus> {
let Ok(txid) = bitcoin::Txid::from_str(&txid) else {
return Err(Error::InvalidTxid);
};
let txid = Txid::from(txid);
// First check mempool for unconfirmed transactions
if let Some(mempool) = query.mempool()
&& mempool.get_txs().contains_key(&txid)
{
return Ok(TxStatus::UNCONFIRMED);
}
// Look up confirmed transaction by txid prefix
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 block info for status
let height = indexer.vecs.tx.txindex_to_height.read_once(txindex)?;
let block_hash = indexer.vecs.block.height_to_blockhash.read_once(height)?;
let block_time = indexer.vecs.block.height_to_timestamp.read_once(height)?;
Ok(TxStatus {
confirmed: true,
block_height: Some(height),
block_hash: Some(block_hash),
block_time: Some(block_time),
})
}
@@ -1,12 +1,7 @@
use std::{
fs::File,
io::{Cursor, Read, Seek, SeekFrom},
str::FromStr,
};
use std::{io::Cursor, str::FromStr};
use bitcoin::consensus::Decodable;
use brk_error::{Error, Result};
use brk_reader::XORIndex;
use brk_types::{
Sats, Transaction, TxIn, TxIndex, TxOut, TxStatus, Txid, TxidPath, TxidPrefix, Vout, Weight,
};
@@ -20,6 +15,15 @@ pub fn get_transaction(TxidPath { txid }: TxidPath, query: &Query) -> Result<Tra
};
let txid = Txid::from(txid);
// First check mempool for unconfirmed transactions
if let Some(mempool) = query.mempool()
&& let Some(tx_with_hex) = mempool.get_txs().get(&txid)
{
return Ok(tx_with_hex.tx().clone());
}
// Look up confirmed transaction by txid prefix
let prefix = TxidPrefix::from(&txid);
let indexer = query.indexer();
let Ok(Some(txindex)) = indexer
@@ -45,7 +49,11 @@ pub fn get_transaction_by_index(txindex: TxIndex, query: &Query) -> Result<Trans
let version = indexer.vecs.tx.txindex_to_txversion.read_once(txindex)?;
let lock_time = indexer.vecs.tx.txindex_to_rawlocktime.read_once(txindex)?;
let total_size = indexer.vecs.tx.txindex_to_total_size.read_once(txindex)?;
let first_txinindex = indexer.vecs.tx.txindex_to_first_txinindex.read_once(txindex)?;
let first_txinindex = indexer
.vecs
.tx
.txindex_to_first_txinindex
.read_once(txindex)?;
let position = computer.blks.txindex_to_position.read_once(txindex)?;
// Get block info for status
@@ -53,39 +61,15 @@ pub fn get_transaction_by_index(txindex: TxIndex, query: &Query) -> Result<Trans
let block_time = indexer.vecs.block.height_to_timestamp.read_once(height)?;
// Read and decode the raw transaction from blk file
let blk_index_to_blk_path = reader.blk_index_to_blk_path();
let Some(blk_path) = blk_index_to_blk_path.get(&position.blk_index()) else {
return Err(Error::Str("Failed to get the correct blk file"));
};
let mut xori = XORIndex::default();
xori.add_assign(position.offset() as usize);
let Ok(mut file) = File::open(blk_path) else {
return Err(Error::Str("Failed to open blk file"));
};
if file
.seek(SeekFrom::Start(position.offset() as u64))
.is_err()
{
return Err(Error::Str("Failed to seek position in file"));
}
let mut buffer = vec![0u8; *total_size as usize];
if file.read_exact(&mut buffer).is_err() {
return Err(Error::Str("Failed to read the transaction (read exact)"));
}
xori.bytes(&mut buffer, reader.xor_bytes());
let buffer = reader.read_raw_bytes(position, *total_size as usize)?;
let mut cursor = Cursor::new(buffer);
let Ok(tx) = bitcoin::Transaction::consensus_decode(&mut cursor) else {
return Err(Error::Str("Failed decode the transaction"));
};
let tx = bitcoin::Transaction::consensus_decode(&mut cursor)
.map_err(|_| Error::Str("Failed to decode transaction"))?;
// For iterating through inputs, we need iterators (multiple lookups)
let mut txindex_to_txid_iter = indexer.vecs.tx.txindex_to_txid.iter()?;
let mut txindex_to_first_txoutindex_iter = indexer.vecs.tx.txindex_to_first_txoutindex.iter()?;
let mut txindex_to_first_txoutindex_iter =
indexer.vecs.tx.txindex_to_first_txoutindex.iter()?;
let mut txinindex_to_outpoint_iter = indexer.vecs.txin.txinindex_to_outpoint.iter()?;
let mut txoutindex_to_value_iter = indexer.vecs.txout.txoutindex_to_value.iter()?;
@@ -144,6 +128,12 @@ pub fn get_transaction_by_index(txindex: TxIndex, query: &Query) -> Result<Trans
// Calculate weight before consuming tx.output
let weight = Weight::from(tx.weight());
// Calculate sigop cost
// Note: Using |_| None means P2SH and SegWit sigops won't be counted accurately
// since we don't provide the prevout scripts. This matches mempool tx behavior.
// For accurate counting, we'd need to reconstruct prevout scripts from indexed data.
let total_sigop_cost = tx.total_sigop_cost(|_| None);
// Build outputs
let output: Vec<TxOut> = tx.output.into_iter().map(TxOut::from).collect();
@@ -162,8 +152,8 @@ pub fn get_transaction_by_index(txindex: TxIndex, query: &Query) -> Result<Trans
lock_time,
total_size: *total_size as usize,
weight,
total_sigop_cost: 0, // Would need to calculate from scripts
fee: Sats::ZERO, // Will be computed below
total_sigop_cost,
fee: Sats::ZERO, // Will be computed below
input,
output,
status,
+61 -3
View File
@@ -1,4 +1,5 @@
#![doc = include_str!("../README.md")]
#![allow(clippy::module_inception)]
use std::{collections::BTreeMap, sync::Arc};
@@ -9,8 +10,8 @@ use brk_monitor::Mempool;
use brk_reader::Reader;
use brk_traversable::TreeNode;
use brk_types::{
Address, AddressStats, Format, Height, Index, IndexInfo, Limit, Metric, MetricCount,
Transaction, TxidPath,
Address, AddressStats, BlockInfo, BlockStatus, Format, Height, Index, IndexInfo, Limit,
MempoolInfo, Metric, MetricCount, Transaction, TxStatus, Txid, TxidPath, Utxo,
};
use vecdb::{AnyExportableVec, AnyStoredVec};
@@ -31,7 +32,12 @@ pub use params::{Params, ParamsDeprec, ParamsOpt};
use vecs::Vecs;
use crate::{
chain::{get_address, get_transaction},
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_transaction, get_transaction_hex,
get_transaction_status,
},
vecs::{IndexToVec, MetricToVec},
};
@@ -74,10 +80,62 @@ impl Query {
get_address(address, self)
}
pub fn get_address_txids(
&self,
address: Address,
after_txid: Option<Txid>,
limit: usize,
) -> Result<Vec<Txid>> {
get_address_txids(address, after_txid, limit, self)
}
pub fn get_address_utxos(&self, address: Address) -> Result<Vec<Utxo>> {
get_address_utxos(address, self)
}
pub fn get_transaction(&self, txid: TxidPath) -> Result<Transaction> {
get_transaction(txid, self)
}
pub fn get_transaction_status(&self, txid: TxidPath) -> Result<TxStatus> {
get_transaction_status(txid, self)
}
pub fn get_transaction_hex(&self, txid: TxidPath) -> Result<String> {
get_transaction_hex(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)
}
pub fn get_block_by_height(&self, height: Height) -> Result<BlockInfo> {
get_block_by_height(height, 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)
}
pub fn get_blocks(&self, start_height: Option<Height>) -> Result<Vec<BlockInfo>> {
get_blocks(start_height, self)
}
pub fn get_block_txids(&self, hash: &str) -> Result<Vec<Txid>> {
let height = get_height_by_hash(hash, self)?;
get_block_txids(height, self)
}
pub fn get_mempool_info(&self) -> Result<MempoolInfo> {
get_mempool_info(self)
}
pub fn get_mempool_txids(&self) -> Result<Vec<Txid>> {
get_mempool_txids(self)
}
pub fn match_metric(&self, metric: &Metric, limit: Limit) -> Vec<&'static str> {
self.vecs().matches(metric, limit)
}