mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-04-25 07:09:59 -07:00
global: snapshot
This commit is contained in:
@@ -9,7 +9,6 @@ use brk_types::{
|
||||
Address, AddressStats, Height, Index, IndexInfo, Limit, Metric, MetricCount, Transaction,
|
||||
TreeNode, TxidPath,
|
||||
};
|
||||
#[cfg(feature = "tokio")]
|
||||
use tokio::task::spawn_blocking;
|
||||
|
||||
use crate::{
|
||||
@@ -18,7 +17,6 @@ use crate::{
|
||||
};
|
||||
|
||||
#[derive(Clone)]
|
||||
#[cfg(feature = "tokio")]
|
||||
pub struct AsyncQuery(Query);
|
||||
|
||||
impl AsyncQuery {
|
||||
|
||||
@@ -7,8 +7,10 @@ use std::{
|
||||
use bitcoin::consensus::Decodable;
|
||||
use brk_error::{Error, Result};
|
||||
use brk_reader::XORIndex;
|
||||
use brk_types::{Transaction, Txid, TxidPath, TxidPrefix};
|
||||
use vecdb::TypedVecIterator;
|
||||
use brk_types::{
|
||||
Sats, Transaction, TxIn, TxIndex, TxOut, TxStatus, Txid, TxidPath, TxidPrefix, Vout, Weight,
|
||||
};
|
||||
use vecdb::{GenericStoredVec, TypedVecIterator};
|
||||
|
||||
use crate::Query;
|
||||
|
||||
@@ -20,7 +22,7 @@ pub fn get_transaction(TxidPath { txid }: TxidPath, query: &Query) -> Result<Tra
|
||||
let txid = Txid::from(txid);
|
||||
let prefix = TxidPrefix::from(&txid);
|
||||
let indexer = query.indexer();
|
||||
let Ok(Some(index)) = indexer
|
||||
let Ok(Some(txindex)) = indexer
|
||||
.stores
|
||||
.txidprefix_to_txindex
|
||||
.get(&prefix)
|
||||
@@ -29,16 +31,29 @@ pub fn get_transaction(TxidPath { txid }: TxidPath, query: &Query) -> Result<Tra
|
||||
return Err(Error::UnknownTxid);
|
||||
};
|
||||
|
||||
let txid = indexer.vecs.txindex_to_txid.iter()?.get_unwrap(index);
|
||||
get_transaction_by_index(txindex, query)
|
||||
}
|
||||
|
||||
pub fn get_transaction_by_index(txindex: TxIndex, query: &Query) -> Result<Transaction> {
|
||||
let indexer = query.indexer();
|
||||
let reader = query.reader();
|
||||
let computer = query.computer();
|
||||
|
||||
let position = computer.blks.txindex_to_position.iter()?.get_unwrap(index);
|
||||
let len = indexer.vecs.txindex_to_total_size.iter()?.get_unwrap(index);
|
||||
// Get tx metadata using read_once for single lookups
|
||||
let txid = indexer.vecs.tx.txindex_to_txid.read_once(txindex)?;
|
||||
let height = indexer.vecs.tx.txindex_to_height.read_once(txindex)?;
|
||||
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 position = computer.blks.txindex_to_position.read_once(txindex)?;
|
||||
|
||||
// Get block info for status
|
||||
let block_hash = indexer.vecs.block.height_to_blockhash.read_once(height)?;
|
||||
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"));
|
||||
};
|
||||
@@ -57,22 +72,105 @@ pub fn get_transaction(TxidPath { txid }: TxidPath, query: &Query) -> Result<Tra
|
||||
return Err(Error::Str("Failed to seek position in file"));
|
||||
}
|
||||
|
||||
let mut buffer = vec![0u8; *len as usize];
|
||||
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 mut reader = Cursor::new(buffer);
|
||||
let Ok(tx) = bitcoin::Transaction::consensus_decode(&mut reader) else {
|
||||
let mut cursor = Cursor::new(buffer);
|
||||
let Ok(tx) = bitcoin::Transaction::consensus_decode(&mut cursor) else {
|
||||
return Err(Error::Str("Failed decode the transaction"));
|
||||
};
|
||||
|
||||
todo!();
|
||||
// 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 txinindex_to_outpoint_iter = indexer.vecs.txin.txinindex_to_outpoint.iter()?;
|
||||
let mut txoutindex_to_value_iter = indexer.vecs.txout.txoutindex_to_value.iter()?;
|
||||
|
||||
// Ok(TxInfo {
|
||||
// txid,
|
||||
// index,
|
||||
// // tx
|
||||
// })
|
||||
// Build inputs with prevout information
|
||||
let input: Vec<TxIn> = tx
|
||||
.input
|
||||
.iter()
|
||||
.enumerate()
|
||||
.map(|(i, txin)| {
|
||||
let txinindex = first_txinindex + i;
|
||||
let outpoint = txinindex_to_outpoint_iter.get_unwrap(txinindex);
|
||||
|
||||
let is_coinbase = outpoint.is_coinbase();
|
||||
|
||||
// Get prevout info if not coinbase
|
||||
let (prev_txid, prev_vout, prevout) = if is_coinbase {
|
||||
(Txid::COINBASE, Vout::MAX, None)
|
||||
} else {
|
||||
let prev_txindex = outpoint.txindex();
|
||||
let prev_vout = outpoint.vout();
|
||||
let prev_txid = txindex_to_txid_iter.get_unwrap(prev_txindex);
|
||||
|
||||
// Calculate the txoutindex for the prevout
|
||||
let prev_first_txoutindex =
|
||||
txindex_to_first_txoutindex_iter.get_unwrap(prev_txindex);
|
||||
let prev_txoutindex = prev_first_txoutindex + prev_vout;
|
||||
|
||||
// Get the value of the prevout
|
||||
let prev_value = txoutindex_to_value_iter.get_unwrap(prev_txoutindex);
|
||||
|
||||
// We don't have the script_pubkey stored directly, so we need to reconstruct
|
||||
// For now, we'll get it from the decoded transaction's witness/scriptsig
|
||||
// which can reveal the prevout script type, but the actual script needs
|
||||
// to be fetched from the spending tx or reconstructed from address bytes
|
||||
let prevout = Some(TxOut::from((
|
||||
bitcoin::ScriptBuf::new(), // Placeholder - would need to reconstruct
|
||||
prev_value,
|
||||
)));
|
||||
|
||||
(prev_txid, prev_vout, prevout)
|
||||
};
|
||||
|
||||
TxIn {
|
||||
txid: prev_txid,
|
||||
vout: prev_vout,
|
||||
prevout,
|
||||
script_sig: txin.script_sig.clone(),
|
||||
script_sig_asm: (),
|
||||
is_coinbase,
|
||||
sequence: txin.sequence.0,
|
||||
inner_redeem_script_asm: (),
|
||||
}
|
||||
})
|
||||
.collect();
|
||||
|
||||
// Calculate weight before consuming tx.output
|
||||
let weight = Weight::from(tx.weight());
|
||||
|
||||
// Build outputs
|
||||
let output: Vec<TxOut> = tx.output.into_iter().map(TxOut::from).collect();
|
||||
|
||||
// Build status
|
||||
let status = TxStatus {
|
||||
confirmed: true,
|
||||
block_height: Some(height),
|
||||
block_hash: Some(block_hash),
|
||||
block_time: Some(block_time),
|
||||
};
|
||||
|
||||
let mut transaction = Transaction {
|
||||
index: Some(txindex),
|
||||
txid,
|
||||
version,
|
||||
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
|
||||
input,
|
||||
output,
|
||||
status,
|
||||
};
|
||||
|
||||
// Compute fee from inputs - outputs
|
||||
transaction.compute_fee();
|
||||
|
||||
Ok(transaction)
|
||||
}
|
||||
|
||||
@@ -14,6 +14,7 @@ use brk_types::{
|
||||
};
|
||||
use vecdb::{AnyExportableVec, AnyStoredVec};
|
||||
|
||||
#[cfg(feature = "tokio")]
|
||||
mod r#async;
|
||||
mod chain;
|
||||
mod deser;
|
||||
@@ -22,6 +23,7 @@ mod pagination;
|
||||
mod params;
|
||||
mod vecs;
|
||||
|
||||
#[cfg(feature = "tokio")]
|
||||
pub use r#async::*;
|
||||
pub use output::{Output, Value};
|
||||
pub use pagination::{PaginatedIndexParam, PaginatedMetrics, PaginationParam};
|
||||
@@ -65,7 +67,7 @@ impl Query {
|
||||
}
|
||||
|
||||
pub fn get_height(&self) -> Height {
|
||||
Height::from(self.indexer().vecs.height_to_blockhash.stamp())
|
||||
Height::from(self.indexer().vecs.block.height_to_blockhash.stamp())
|
||||
}
|
||||
|
||||
pub fn get_address(&self, address: Address) -> Result<AddressStats> {
|
||||
|
||||
Reference in New Issue
Block a user