mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-07-01 06:19:02 -07:00
crates: snapshot
This commit is contained in:
@@ -85,25 +85,6 @@ impl Query {
|
||||
})
|
||||
}
|
||||
|
||||
/// Esplora `/address/:address/txs` first page: up to `mempool_limit`
|
||||
/// mempool entries (newest first), then chain entries fill the response
|
||||
/// up to `total_limit`. Pagination is path-style via `/txs/chain/:after_txid`.
|
||||
pub fn addr_txs(
|
||||
&self,
|
||||
addr: Addr,
|
||||
total_limit: usize,
|
||||
mempool_limit: usize,
|
||||
) -> Result<Vec<Transaction>> {
|
||||
let mut out = if self.mempool().is_some() {
|
||||
self.addr_mempool_txs(&addr, mempool_limit)?
|
||||
} else {
|
||||
Vec::new()
|
||||
};
|
||||
let chain_limit = total_limit.saturating_sub(out.len());
|
||||
out.extend(self.addr_txs_chain(&addr, None, chain_limit)?);
|
||||
Ok(out)
|
||||
}
|
||||
|
||||
pub fn addr_txs_chain(
|
||||
&self,
|
||||
addr: &Addr,
|
||||
@@ -236,8 +217,15 @@ impl Query {
|
||||
Ok(mempool.addr_txs(&bytes, limit))
|
||||
}
|
||||
|
||||
/// Height of the last on-chain activity for an address (last tx_index → height).
|
||||
pub fn addr_last_activity_height(&self, addr: &Addr) -> Result<Height> {
|
||||
/// Height of the last on-chain activity for an address (last tx_index to height).
|
||||
/// With `before_txid`, returns the newest activity strictly older than that
|
||||
/// cursor. Used by paginated chain etags so a new tx above the cursor
|
||||
/// doesn't invalidate deeper pages.
|
||||
pub fn addr_last_activity_height(
|
||||
&self,
|
||||
addr: &Addr,
|
||||
before_txid: Option<&Txid>,
|
||||
) -> Result<Height> {
|
||||
let (output_type, type_index) = self.resolve_addr(addr)?;
|
||||
let store = self
|
||||
.indexer()
|
||||
@@ -246,12 +234,25 @@ impl Query {
|
||||
.get(output_type)
|
||||
.data()?;
|
||||
let tx_index_len = self.safe_lengths().tx_index;
|
||||
let last_tx_index = store
|
||||
.prefix(type_index)
|
||||
.rev()
|
||||
.map(|(key, _): (AddrIndexTxIndex, Unit)| key.tx_index())
|
||||
.find(|tx_index| *tx_index < tx_index_len)
|
||||
.ok_or(Error::UnknownAddr)?;
|
||||
let last_tx_index = match before_txid {
|
||||
Some(txid) => {
|
||||
let before_tx_index = self.resolve_tx_index(txid)?;
|
||||
let min = AddrIndexTxIndex::min_for_addr(type_index);
|
||||
let cursor = AddrIndexTxIndex::from((type_index, before_tx_index));
|
||||
store
|
||||
.range(min..cursor)
|
||||
.rev()
|
||||
.map(|(key, _): (AddrIndexTxIndex, Unit)| key.tx_index())
|
||||
.find(|tx_index| *tx_index < tx_index_len)
|
||||
.ok_or(Error::UnknownAddr)?
|
||||
}
|
||||
None => store
|
||||
.prefix(type_index)
|
||||
.rev()
|
||||
.map(|(key, _): (AddrIndexTxIndex, Unit)| key.tx_index())
|
||||
.find(|tx_index| *tx_index < tx_index_len)
|
||||
.ok_or(Error::UnknownAddr)?,
|
||||
};
|
||||
self.confirmed_status_height(last_tx_index)
|
||||
}
|
||||
|
||||
|
||||
@@ -1,20 +1,68 @@
|
||||
use brk_error::Result;
|
||||
use std::sync::Arc;
|
||||
|
||||
use brk_computer::prices::Vecs as PricesVecs;
|
||||
use brk_error::{Error, Result};
|
||||
use brk_oracle::{Config, Oracle, cents_to_bin};
|
||||
use brk_types::{
|
||||
Dollars, ExchangeRates, HistoricalPrice, HistoricalPriceEntry, Hour4, INDEX_EPOCH, Timestamp,
|
||||
};
|
||||
use vecdb::ReadableVec;
|
||||
use vecdb::{AnyVec, ReadableVec, VecIndex};
|
||||
|
||||
use crate::Query;
|
||||
|
||||
impl Query {
|
||||
pub fn live_price(&self) -> Result<Dollars> {
|
||||
let mut oracle = self.computer().prices.live_oracle(self.indexer())?;
|
||||
let base = self.cached_oracle()?;
|
||||
Ok(match self.mempool() {
|
||||
Some(mempool) => {
|
||||
let mut oracle = (*base).clone();
|
||||
oracle.process_histogram(&mempool.live_histogram());
|
||||
oracle.price_dollars()
|
||||
}
|
||||
None => base.price_dollars(),
|
||||
})
|
||||
}
|
||||
|
||||
if let Some(mempool) = self.mempool() {
|
||||
mempool.process_live_outputs(|iter| oracle.process_outputs(iter));
|
||||
/// Oracle warmed by the last `window_size` committed blocks, seeded from
|
||||
/// the last committed price. Cached per tip height; rebuilt on advance or
|
||||
/// reorg. Reads are capped at `safe_lengths` so concurrent indexer writes
|
||||
/// stay invisible.
|
||||
fn cached_oracle(&self) -> Result<Arc<Oracle>> {
|
||||
let safe_lengths = self.safe_lengths();
|
||||
let height = safe_lengths.height;
|
||||
|
||||
if let Some(oracle) = self
|
||||
.0
|
||||
.live_oracle
|
||||
.read()
|
||||
.unwrap()
|
||||
.as_ref()
|
||||
.filter(|(h, _)| *h == height)
|
||||
.map(|(_, o)| o.clone())
|
||||
{
|
||||
return Ok(oracle);
|
||||
}
|
||||
|
||||
Ok(oracle.price_dollars())
|
||||
let cents_height = &self.computer().prices.spot.cents.height;
|
||||
let last_cents = cents_height
|
||||
.len()
|
||||
.checked_sub(1)
|
||||
.and_then(|i| cents_height.collect_one_at(i))
|
||||
.ok_or_else(|| Error::NotFound("oracle prices not yet computed".to_string()))?;
|
||||
|
||||
let config = Config::default();
|
||||
let seed_bin = cents_to_bin(last_cents.inner() as f64);
|
||||
let tip = height.to_usize();
|
||||
let warmup_range = tip.saturating_sub(config.window_size)..tip;
|
||||
let oracle = Arc::new(Oracle::from_checkpoint(seed_bin, config, |o| {
|
||||
PricesVecs::feed_blocks(o, self.indexer(), warmup_range, Some(&safe_lengths));
|
||||
}));
|
||||
|
||||
let mut cache = self.0.live_oracle.write().unwrap();
|
||||
if cache.as_ref().is_none_or(|(h, _)| *h != height) {
|
||||
*cache = Some((height, oracle.clone()));
|
||||
}
|
||||
Ok(oracle)
|
||||
}
|
||||
|
||||
pub fn historical_price(&self, timestamp: Option<Timestamp>) -> Result<HistoricalPrice> {
|
||||
|
||||
@@ -1,12 +1,16 @@
|
||||
#![doc = include_str!("../README.md")]
|
||||
#![allow(clippy::module_inception)]
|
||||
|
||||
use std::{path::Path, sync::Arc};
|
||||
use std::{
|
||||
path::Path,
|
||||
sync::{Arc, RwLock},
|
||||
};
|
||||
|
||||
use brk_computer::Computer;
|
||||
use brk_error::{OptionData, Result};
|
||||
use brk_indexer::{Indexer, Lengths};
|
||||
use brk_mempool::Mempool;
|
||||
use brk_oracle::Oracle;
|
||||
use brk_reader::Reader;
|
||||
use brk_rpc::Client;
|
||||
use brk_types::{BlockHash, BlockHashPrefix, Height, SyncStatus};
|
||||
@@ -32,6 +36,7 @@ struct QueryInner<'a> {
|
||||
indexer: &'a Indexer<Ro>,
|
||||
computer: &'a Computer<Ro>,
|
||||
mempool: Option<Mempool>,
|
||||
live_oracle: RwLock<Option<(Height, Arc<Oracle>)>>,
|
||||
}
|
||||
|
||||
impl Query {
|
||||
@@ -54,6 +59,7 @@ impl Query {
|
||||
indexer,
|
||||
computer,
|
||||
mempool,
|
||||
live_oracle: RwLock::new(None),
|
||||
}))
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user