mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-07-11 11:08:13 -07:00
global: fixes
This commit is contained in:
@@ -142,7 +142,8 @@ 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_utxos(path.addr, 1000)).await
|
||||
let max_utxos = state.max_utxos;
|
||||
state.respond_json(&headers, strategy, &uri, move |q| q.addr_utxos(path.addr, max_utxos)).await
|
||||
}, |op| op
|
||||
.id("get_address_utxos")
|
||||
.addrs_tag()
|
||||
|
||||
@@ -3,10 +3,9 @@ use axum::{
|
||||
extract::{Path, State},
|
||||
http::{HeaderMap, Uri},
|
||||
};
|
||||
use brk_query::BLOCK_TXS_PAGE_SIZE;
|
||||
use brk_types::{
|
||||
BlockHash, BlockInfo, BlockInfoV1, BlockStatus, BlockTimestamp, Height, Hex, Transaction,
|
||||
TxIndex, Txid, Version,
|
||||
BlockHash, BlockInfo, BlockInfoV1, BlockStatus, BlockTimestamp, BlockTxIndex, Height, Hex,
|
||||
Transaction, Txid, Version,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
@@ -17,6 +16,8 @@ use crate::{
|
||||
},
|
||||
};
|
||||
|
||||
const BLOCK_TXS_PAGE_SIZE: u32 = 25;
|
||||
|
||||
pub trait BlockRoutes {
|
||||
fn add_block_routes(self) -> Self;
|
||||
}
|
||||
@@ -278,7 +279,7 @@ impl BlockRoutes for ApiRouter<AppState> {
|
||||
Path(path): Path<BlockHashParam>,
|
||||
_: Empty, State(state): State<AppState>| {
|
||||
let strategy = state.block_strategy(Version::ONE, &path.hash);
|
||||
state.respond_json(&headers, strategy, &uri, move |q| q.block_txs(&path.hash, TxIndex::default())).await
|
||||
state.respond_json(&headers, strategy, &uri, move |q| q.block_txs(&path.hash, BlockTxIndex::default(), BLOCK_TXS_PAGE_SIZE)).await
|
||||
},
|
||||
|op| {
|
||||
op.id("get_block_txs")
|
||||
@@ -304,7 +305,7 @@ impl BlockRoutes for ApiRouter<AppState> {
|
||||
Path(path): Path<BlockHashStartIndex>,
|
||||
_: Empty, State(state): State<AppState>| {
|
||||
let strategy = state.block_strategy(Version::ONE, &path.hash);
|
||||
state.respond_json(&headers, strategy, &uri, move |q| q.block_txs(&path.hash, path.start_index)).await
|
||||
state.respond_json(&headers, strategy, &uri, move |q| q.block_txs(&path.hash, path.start_index, BLOCK_TXS_PAGE_SIZE)).await
|
||||
},
|
||||
|op| {
|
||||
op.id("get_block_txs_from_index")
|
||||
|
||||
@@ -44,7 +44,7 @@ impl ApiMetricsLegacyRoutes for ApiRouter<AppState> {
|
||||
"/api/metrics",
|
||||
get_with(
|
||||
async |uri: Uri, headers: HeaderMap, _: Empty, State(state): State<AppState>| {
|
||||
state.respond_json(&headers, CacheStrategy::Deploy, &uri, |q| Ok(q.series_catalog().clone())).await
|
||||
state.respond_json(&headers, CacheStrategy::Deploy, &uri, |q| Ok(q.series_catalog())).await
|
||||
},
|
||||
|op| op
|
||||
.id("get_metrics_tree_deprecated")
|
||||
@@ -92,7 +92,7 @@ impl ApiMetricsLegacyRoutes for ApiRouter<AppState> {
|
||||
_: Empty,
|
||||
State(state): State<AppState>
|
||||
| {
|
||||
state.respond_json(&headers, CacheStrategy::Deploy, &uri, |q| Ok(q.indexes().to_vec())).await
|
||||
state.respond_json(&headers, CacheStrategy::Deploy, &uri, |q| Ok(q.indexes())).await
|
||||
},
|
||||
|op| op
|
||||
.id("get_indexes_deprecated")
|
||||
|
||||
@@ -15,6 +15,9 @@ use crate::{
|
||||
params::{BlockCountParam, Empty, PoolSlugAndHeightParam, PoolSlugParam, TimePeriodParam},
|
||||
};
|
||||
|
||||
const HASHRATE_MAX_POINTS: usize = 200;
|
||||
const POOL_BLOCKS_LIMIT: usize = 100;
|
||||
|
||||
pub trait MiningRoutes {
|
||||
fn add_mining_routes(self) -> Self;
|
||||
}
|
||||
@@ -132,7 +135,7 @@ impl MiningRoutes for ApiRouter<AppState> {
|
||||
"/api/v1/mining/pool/{slug}/blocks",
|
||||
get_with(
|
||||
async |uri: Uri, headers: HeaderMap, Path(path): Path<PoolSlugParam>, _: Empty, State(state): State<AppState>| {
|
||||
state.respond_json(&headers, CacheStrategy::Tip, &uri, move |q| q.pool_blocks(path.slug, None)).await
|
||||
state.respond_json(&headers, CacheStrategy::Tip, &uri, move |q| q.pool_blocks(path.slug, None, POOL_BLOCKS_LIMIT)).await
|
||||
},
|
||||
|op| {
|
||||
op.id("get_pool_blocks")
|
||||
@@ -150,7 +153,7 @@ impl MiningRoutes for ApiRouter<AppState> {
|
||||
"/api/v1/mining/pool/{slug}/blocks/{height}",
|
||||
get_with(
|
||||
async |uri: Uri, headers: HeaderMap, Path(PoolSlugAndHeightParam {slug, height}): Path<PoolSlugAndHeightParam>, _: Empty, State(state): State<AppState>| {
|
||||
state.respond_json(&headers, state.height_strategy(Version::ONE, height), &uri, move |q| q.pool_blocks(slug, Some(height))).await
|
||||
state.respond_json(&headers, state.height_strategy(Version::ONE, height), &uri, move |q| q.pool_blocks(slug, Some(height), POOL_BLOCKS_LIMIT)).await
|
||||
},
|
||||
|op| {
|
||||
op.id("get_pool_blocks_from")
|
||||
@@ -168,7 +171,7 @@ impl MiningRoutes for ApiRouter<AppState> {
|
||||
"/api/v1/mining/hashrate",
|
||||
get_with(
|
||||
async |uri: Uri, headers: HeaderMap, _: Empty, State(state): State<AppState>| {
|
||||
state.respond_json(&headers, CacheStrategy::Tip, &uri, |q| q.hashrate(None)).await
|
||||
state.respond_json(&headers, CacheStrategy::Tip, &uri, |q| q.hashrate(None, HASHRATE_MAX_POINTS)).await
|
||||
},
|
||||
|op| {
|
||||
op.id("get_hashrate")
|
||||
@@ -185,7 +188,7 @@ impl MiningRoutes for ApiRouter<AppState> {
|
||||
"/api/v1/mining/hashrate/{time_period}",
|
||||
get_with(
|
||||
async |uri: Uri, headers: HeaderMap, Path(path): Path<TimePeriodParam>, _: Empty, State(state): State<AppState>| {
|
||||
state.respond_json(&headers, CacheStrategy::Tip, &uri, move |q| q.hashrate(Some(path.time_period))).await
|
||||
state.respond_json(&headers, CacheStrategy::Tip, &uri, move |q| q.hashrate(Some(path.time_period), HASHRATE_MAX_POINTS)).await
|
||||
},
|
||||
|op| {
|
||||
op.id("get_hashrate_by_period")
|
||||
|
||||
@@ -108,7 +108,7 @@ impl ApiSeriesRoutes for ApiRouter<AppState> {
|
||||
"/api/series",
|
||||
get_with(
|
||||
async |uri: Uri, headers: HeaderMap, _: Empty, State(state): State<AppState>| {
|
||||
state.respond_json(&headers, CacheStrategy::Deploy, &uri, |q| Ok(q.series_catalog().clone())).await
|
||||
state.respond_json(&headers, CacheStrategy::Deploy, &uri, |q| Ok(q.series_catalog())).await
|
||||
},
|
||||
|op| op
|
||||
.id("get_series_tree")
|
||||
@@ -151,7 +151,7 @@ impl ApiSeriesRoutes for ApiRouter<AppState> {
|
||||
_: Empty,
|
||||
State(state): State<AppState>
|
||||
| {
|
||||
state.respond_json(&headers, CacheStrategy::Deploy, &uri, |q| Ok(q.indexes().to_vec())).await
|
||||
state.respond_json(&headers, CacheStrategy::Deploy, &uri, |q| Ok(q.indexes())).await
|
||||
},
|
||||
|op| op
|
||||
.id("get_indexes")
|
||||
|
||||
@@ -8,6 +8,10 @@ use crate::cache::CdnCacheMode;
|
||||
/// 50 MB - generous enough for any honest query, low enough to limit cache-buster leverage.
|
||||
pub const DEFAULT_MAX_WEIGHT: usize = 50 * 1_000_000;
|
||||
|
||||
/// Default max UTXOs returned per address.
|
||||
/// Bounds worst-case work and response size, prevents heavy-address DDoS.
|
||||
pub const DEFAULT_MAX_UTXOS: usize = 1000;
|
||||
|
||||
/// Server-wide configuration set at startup.
|
||||
#[derive(Debug, Clone)]
|
||||
pub struct ServerConfig {
|
||||
@@ -15,6 +19,7 @@ pub struct ServerConfig {
|
||||
pub website: Website,
|
||||
pub cdn_cache_mode: CdnCacheMode,
|
||||
pub max_weight: usize,
|
||||
pub max_utxos: usize,
|
||||
}
|
||||
|
||||
impl Default for ServerConfig {
|
||||
@@ -24,6 +29,7 @@ impl Default for ServerConfig {
|
||||
website: Website::default(),
|
||||
cdn_cache_mode: CdnCacheMode::default(),
|
||||
max_weight: DEFAULT_MAX_WEIGHT,
|
||||
max_utxos: DEFAULT_MAX_UTXOS,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -50,7 +50,7 @@ pub use brk_types::Port;
|
||||
pub use brk_website::Website;
|
||||
pub use cache::CdnCacheMode;
|
||||
use cache::{CacheParams, CacheStrategy};
|
||||
pub use config::{DEFAULT_MAX_WEIGHT, ServerConfig};
|
||||
pub use config::{DEFAULT_MAX_UTXOS, DEFAULT_MAX_WEIGHT, ServerConfig};
|
||||
pub use error::{Error, Result};
|
||||
use state::*;
|
||||
|
||||
@@ -84,6 +84,7 @@ impl Server {
|
||||
started_at: jiff::Timestamp::now(),
|
||||
started_instant: Instant::now(),
|
||||
max_weight: config.max_weight,
|
||||
max_utxos: config.max_utxos,
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
|
||||
use brk_types::{BlockHash, TxIndex};
|
||||
use brk_types::{BlockHash, BlockTxIndex};
|
||||
|
||||
/// Block hash + starting transaction index path parameters
|
||||
#[derive(Deserialize, JsonSchema)]
|
||||
@@ -11,5 +11,5 @@ pub struct BlockHashStartIndex {
|
||||
|
||||
/// Starting transaction index within the block (0-based)
|
||||
#[schemars(example = 0)]
|
||||
pub start_index: TxIndex,
|
||||
pub start_index: BlockTxIndex,
|
||||
}
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
|
||||
use brk_types::{BlockHash, TxIndex};
|
||||
use brk_types::{BlockHash, BlockTxIndex};
|
||||
|
||||
/// Block hash + transaction index path parameters
|
||||
#[derive(Deserialize, JsonSchema)]
|
||||
@@ -11,5 +11,5 @@ pub struct BlockHashTxIndex {
|
||||
|
||||
/// Transaction index within the block (0-based)
|
||||
#[schemars(example = 0)]
|
||||
pub index: TxIndex,
|
||||
pub index: BlockTxIndex,
|
||||
}
|
||||
|
||||
@@ -25,6 +25,7 @@ pub struct AppState {
|
||||
pub started_at: Timestamp,
|
||||
pub started_instant: Instant,
|
||||
pub max_weight: usize,
|
||||
pub max_utxos: usize,
|
||||
}
|
||||
|
||||
impl AppState {
|
||||
|
||||
Reference in New Issue
Block a user