mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-05-19 06:14:47 -07:00
global: fixes
This commit is contained in:
@@ -9026,7 +9026,7 @@ impl BrkClient {
|
||||
|
||||
/// Address transactions
|
||||
///
|
||||
/// Get transaction history for an address, sorted with newest first. Returns up to 50 mempool transactions plus the first 25 confirmed transactions. To paginate further confirmed transactions, use `/address/{address}/txs/chain/{last_seen_txid}`.
|
||||
/// Get transaction history for an address, sorted with newest first. Returns up to 50 entries: mempool transactions first, then confirmed transactions filling the remainder. To paginate further confirmed transactions, use `/address/{address}/txs/chain/{last_seen_txid}`.
|
||||
///
|
||||
/// *[Mempool.space docs](https://mempool.space/docs/api/rest#get-address-transactions)*
|
||||
///
|
||||
|
||||
@@ -90,19 +90,20 @@ impl Query {
|
||||
}
|
||||
|
||||
/// Esplora `/address/:address/txs` first page: up to `mempool_limit`
|
||||
/// mempool (newest first) followed by the first `chain_limit`
|
||||
/// confirmed. Pagination is path-style via `/txs/chain/:after_txid`.
|
||||
/// 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,
|
||||
chain_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)
|
||||
}
|
||||
|
||||
@@ -16,7 +16,9 @@ impl Query {
|
||||
|
||||
let max_height = Height::from(indexer.vecs.blocks.blockhash.len().saturating_sub(1));
|
||||
if height > max_height {
|
||||
return Err(Error::OutOfRange("Block height out of range".into()));
|
||||
return Err(Error::OutOfRange(format!(
|
||||
"Block height {height} out of range (tip {max_height})"
|
||||
)));
|
||||
}
|
||||
|
||||
let position = indexer.vecs.blocks.position.collect_one(height).data()?;
|
||||
|
||||
@@ -13,25 +13,25 @@ use crate::Query;
|
||||
const RECENT_REPLACEMENTS_LIMIT: usize = 25;
|
||||
|
||||
impl Query {
|
||||
fn require_mempool(&self) -> Result<&Mempool> {
|
||||
self.mempool().ok_or(Error::MempoolNotAvailable)
|
||||
}
|
||||
|
||||
pub fn mempool_info(&self) -> Result<MempoolInfo> {
|
||||
let mempool = self.mempool().ok_or(Error::MempoolNotAvailable)?;
|
||||
Ok(mempool.info())
|
||||
Ok(self.require_mempool()?.info())
|
||||
}
|
||||
|
||||
pub fn mempool_txids(&self) -> Result<Vec<Txid>> {
|
||||
let mempool = self.mempool().ok_or(Error::MempoolNotAvailable)?;
|
||||
let txs = mempool.txs();
|
||||
let txs = self.require_mempool()?.txs();
|
||||
Ok(txs.keys().cloned().collect())
|
||||
}
|
||||
|
||||
pub fn recommended_fees(&self) -> Result<RecommendedFees> {
|
||||
self.mempool()
|
||||
.map(|mempool| mempool.fees())
|
||||
.ok_or(Error::MempoolNotAvailable)
|
||||
self.require_mempool().map(|m| m.fees())
|
||||
}
|
||||
|
||||
pub fn mempool_blocks(&self) -> Result<Vec<MempoolBlock>> {
|
||||
let mempool = self.mempool().ok_or(Error::MempoolNotAvailable)?;
|
||||
let mempool = self.require_mempool()?;
|
||||
|
||||
let block_stats = mempool.block_stats();
|
||||
|
||||
@@ -90,8 +90,7 @@ impl Query {
|
||||
}
|
||||
|
||||
pub fn mempool_recent(&self) -> Result<Vec<MempoolRecentTx>> {
|
||||
let mempool = self.mempool().ok_or(Error::MempoolNotAvailable)?;
|
||||
Ok(mempool.txs().recent().to_vec())
|
||||
Ok(self.require_mempool()?.txs().recent().to_vec())
|
||||
}
|
||||
|
||||
/// CPFP cluster for `txid`. Returns the mempool cluster when the txid is
|
||||
@@ -289,7 +288,7 @@ impl Query {
|
||||
/// walks `predecessors_of` backward to build the tree. `replaces`
|
||||
/// is the requested tx's own direct predecessors.
|
||||
pub fn tx_rbf(&self, txid: &Txid) -> Result<RbfResponse> {
|
||||
let mempool = self.mempool().ok_or(Error::MempoolNotAvailable)?;
|
||||
let mempool = self.require_mempool()?;
|
||||
let txs = mempool.txs();
|
||||
let entries = mempool.entries();
|
||||
let graveyard = mempool.graveyard();
|
||||
@@ -422,7 +421,7 @@ impl Query {
|
||||
/// true, only trees with at least one non-signaling predecessor
|
||||
/// are returned.
|
||||
pub fn recent_replacements(&self, full_rbf_only: bool) -> Result<Vec<ReplacementNode>> {
|
||||
let mempool = self.mempool().ok_or(Error::MempoolNotAvailable)?;
|
||||
let mempool = self.require_mempool()?;
|
||||
let txs = mempool.txs();
|
||||
let entries = mempool.entries();
|
||||
let graveyard = mempool.graveyard();
|
||||
@@ -450,15 +449,17 @@ impl Query {
|
||||
.collect())
|
||||
}
|
||||
|
||||
/// `first_seen` Unix-second timestamps for each txid, matching
|
||||
/// mempool.space's `POST /api/v1/transaction-times`. Returns 0 for
|
||||
/// unknown txids, in input order.
|
||||
pub fn transaction_times(&self, txids: &[Txid]) -> Result<Vec<u64>> {
|
||||
let mempool = self.mempool().ok_or(Error::MempoolNotAvailable)?;
|
||||
let entries = mempool.entries();
|
||||
let entries = self.require_mempool()?.entries();
|
||||
Ok(txids
|
||||
.iter()
|
||||
.map(|txid| {
|
||||
entries
|
||||
.get(&TxidPrefix::from(txid))
|
||||
.map(|e| usize::from(e.first_seen) as u64)
|
||||
.map(|e| u64::from(e.first_seen))
|
||||
.unwrap_or(0)
|
||||
})
|
||||
.collect())
|
||||
|
||||
@@ -65,8 +65,17 @@ impl Query {
|
||||
TARGET_BLOCK_TIME
|
||||
};
|
||||
|
||||
// Per-block time needed over remaining blocks to land the epoch at
|
||||
// 2016 * TARGET_BLOCK_TIME. Matches mempool.space's adjustedTimeAvg.
|
||||
let target_total = BLOCKS_PER_EPOCH as u64 * TARGET_BLOCK_TIME;
|
||||
let adjusted_time_avg = if remaining_blocks > 0 {
|
||||
target_total.saturating_sub(elapsed_time) / remaining_blocks as u64
|
||||
} else {
|
||||
TARGET_BLOCK_TIME
|
||||
};
|
||||
|
||||
// Estimate remaining time and retarget date
|
||||
let remaining_time = remaining_blocks as u64 * time_avg;
|
||||
let remaining_time = remaining_blocks as u64 * adjusted_time_avg;
|
||||
let now = SystemTime::now()
|
||||
.duration_since(UNIX_EPOCH)
|
||||
.map(|d| d.as_secs())
|
||||
@@ -131,7 +140,7 @@ impl Query {
|
||||
previous_time,
|
||||
next_retarget_height: Height::from(next_retarget_height),
|
||||
time_avg: time_avg * 1000,
|
||||
adjusted_time_avg: time_avg * 1000,
|
||||
adjusted_time_avg: adjusted_time_avg * 1000,
|
||||
time_offset,
|
||||
expected_blocks,
|
||||
})
|
||||
|
||||
@@ -50,12 +50,12 @@ impl AddrRoutes for ApiRouter<AppState> {
|
||||
State(state): State<AppState>
|
||||
| {
|
||||
let strategy = state.addr_strategy(Version::ONE, &path.addr, false);
|
||||
state.respond_json(&headers, strategy, &uri, move |q| q.addr_txs(path.addr, 50, 25)).await
|
||||
state.respond_json(&headers, strategy, &uri, move |q| q.addr_txs(path.addr, 50, 50)).await
|
||||
}, |op| op
|
||||
.id("get_address_txs")
|
||||
.addrs_tag()
|
||||
.summary("Address transactions")
|
||||
.description("Get transaction history for an address, sorted with newest first. Returns up to 50 mempool transactions plus the first 25 confirmed transactions. To paginate further confirmed transactions, use `/address/{address}/txs/chain/{last_seen_txid}`.\n\n*[Mempool.space docs](https://mempool.space/docs/api/rest#get-address-transactions)*")
|
||||
.description("Get transaction history for an address, sorted with newest first. Returns up to 50 entries: mempool transactions first, then confirmed transactions filling the remainder. To paginate further confirmed transactions, use `/address/{address}/txs/chain/{last_seen_txid}`.\n\n*[Mempool.space docs](https://mempool.space/docs/api/rest#get-address-transactions)*")
|
||||
.json_response::<Vec<Transaction>>()
|
||||
.not_modified()
|
||||
.bad_request()
|
||||
|
||||
@@ -137,6 +137,13 @@ impl From<Timestamp> for usize {
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Timestamp> for u64 {
|
||||
#[inline]
|
||||
fn from(value: Timestamp) -> Self {
|
||||
u64::from(value.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Date> for Timestamp {
|
||||
#[inline]
|
||||
fn from(value: Date) -> Self {
|
||||
|
||||
Reference in New Issue
Block a user