mempool: init

This commit is contained in:
nym21
2025-10-12 17:55:21 +02:00
parent 5f87594ead
commit 7bfca87caf
22 changed files with 317 additions and 125 deletions

View File

@@ -2,7 +2,8 @@ use aide::axum::{ApiRouter, routing::get_with};
use axum::{
extract::{Path, State},
http::HeaderMap,
response::Response,
response::{Redirect, Response},
routing::get,
};
use brk_structs::{AddressInfo, AddressPath};
@@ -13,14 +14,17 @@ use crate::{
use super::AppState;
pub trait AddressesRoutes {
pub trait AddressRoutes {
fn add_addresses_routes(self) -> Self;
}
impl AddressesRoutes for ApiRouter<AppState> {
impl AddressRoutes for ApiRouter<AppState> {
fn add_addresses_routes(self) -> Self {
self.api_route(
"/api/chain/address/{address}",
self
.route("/api/address", get(Redirect::temporary("/api/addresses")))
.route("/api/addresses", get(Redirect::temporary("/api#tag/addresses")))
.api_route(
"/api/address/{address}",
get_with(async |
headers: HeaderMap,
Path(address): Path<AddressPath>,
@@ -35,14 +39,14 @@ impl AddressesRoutes for ApiRouter<AppState> {
Err((status, message)) => Response::new_json_with(status, &message, &etag)
}
}, |op| op
.tag("Chain")
.addresses_tag()
.summary("Address information")
.description("Retrieve comprehensive information about a Bitcoin address including balance, transaction history, UTXOs, and estimated investment metrics. Supports all standard Bitcoin address types (P2PKH, P2SH, P2WPKH, P2WSH, P2TR, etc.).")
.with_ok_response::<AddressInfo, _>(|res| res)
.with_not_modified()
.with_bad_request()
.with_not_found()
.with_server_error()
.ok_response::<AddressInfo>()
.not_modified()
.bad_request()
.not_found()
.server_error()
),
)
}

View File

@@ -1,21 +0,0 @@
use aide::axum::ApiRouter;
use axum::{response::Redirect, routing::get};
use crate::api::chain::{addresses::AddressesRoutes, transactions::TransactionsRoutes};
use super::AppState;
mod addresses;
mod transactions;
pub trait ChainRoutes {
fn add_chain_routes(self) -> Self;
}
impl ChainRoutes for ApiRouter<AppState> {
fn add_chain_routes(self) -> Self {
self.route("/api/chain", get(Redirect::temporary("/api#tag/chain")))
.add_addresses_routes()
.add_transactions_routes()
}
}

View File

@@ -76,10 +76,7 @@ fn req_to_response_res(
// .1
// .etag(Stamp::from(interface.get_height()), to);
// if headers
// .get_if_none_match()
// .is_some_and(|prev_etag| etag == prev_etag)
// {
// if headers.has_etag(etag) {
// return Ok(Response::new_not_modified());
// }

View File

@@ -25,6 +25,7 @@ pub trait ApiMetricsRoutes {
impl ApiMetricsRoutes for ApiRouter<AppState> {
fn add_metrics_routes(self) -> Self {
self
.route("/api/metric", get(Redirect::temporary("/api/metrics")))
.route("/api/metrics", get(Redirect::temporary("/api#tag/metrics")))
.api_route(
"/api/metrics/count",
@@ -39,11 +40,12 @@ impl ApiMetricsRoutes for ApiRouter<AppState> {
}
Response::new_json(state.metric_count(), etag)
},
|op| op.tag("Metrics")
|op| op
.metrics_tag()
.summary("Metric count")
.description("Current metric count")
.with_ok_response::<Vec<MetricCount>, _>(|res| res)
.with_not_modified(),
.ok_response::<Vec<MetricCount>>()
.not_modified(),
),
)
.api_route(
@@ -59,13 +61,14 @@ impl ApiMetricsRoutes for ApiRouter<AppState> {
}
Response::new_json(state.get_indexes(), etag)
},
|op| op.tag("Metrics")
|op| op
.metrics_tag()
.summary("List available indexes")
.description(
"Returns all available indexes with their accepted query aliases. Use any alias when querying metrics."
)
.with_ok_response::<Vec<IndexInfo>, _>(|res| res)
.with_not_modified(),
.ok_response::<Vec<IndexInfo>>()
.not_modified(),
),
)
.api_route(
@@ -82,11 +85,12 @@ impl ApiMetricsRoutes for ApiRouter<AppState> {
}
Response::new_json(state.get_metrics(pagination), etag)
},
|op| op.tag("Metrics")
|op| op
.metrics_tag()
.summary("Metrics list")
.description("Paginated list of available metrics")
.with_ok_response::<PaginatedMetrics, _>(|res| res)
.with_not_modified(),
.ok_response::<PaginatedMetrics>()
.not_modified(),
),
)
.api_route(
@@ -99,13 +103,14 @@ impl ApiMetricsRoutes for ApiRouter<AppState> {
}
Response::new_json(state.get_metrics_catalog(), etag)
},
|op| op.tag("Metrics")
|op| op
.metrics_tag()
.summary("Metrics catalog")
.description(
"Returns the complete hierarchical catalog of available metrics organized as a tree structure. Metrics are grouped by categories and subcategories. Best viewed in an interactive JSON viewer (e.g., Firefox's built-in JSON viewer) for easy navigation of the nested structure."
)
.with_ok_response::<TreeNode, _>(|res| res)
.with_not_modified(),
.ok_response::<TreeNode>()
.not_modified(),
),
)
.api_route(
@@ -122,15 +127,16 @@ impl ApiMetricsRoutes for ApiRouter<AppState> {
}
Response::new_json(state.match_metric(query), etag)
},
|op| op.tag("Metrics")
|op| op
.metrics_tag()
.summary("Search metrics")
.description("Fuzzy search for metrics by name. Supports partial matches and typos.")
.with_ok_response::<Vec<String>, _>(|res| res)
.with_not_modified(),
.ok_response::<Vec<String>>()
.not_modified(),
),
)
.api_route(
"/api/metrics/{metric}",
"/api/metric/{metric}",
get_with(
async |
headers: HeaderMap,
@@ -154,36 +160,38 @@ impl ApiMetricsRoutes for ApiRouter<AppState> {
};
Response::new_json_with(StatusCode::NOT_FOUND, value, etag)
},
|op| op.tag("Metrics")
|op| op
.metrics_tag()
.summary("Get supported indexes for a metric")
.description(
"Returns the list of indexes are supported by the specified metric. \
For example, `realized_price` might be available on dateindex, weekindex, and monthindex."
)
.with_ok_response::<Vec<Index>, _>(|res| res)
.with_not_modified()
.with_not_found(),
.ok_response::<Vec<Index>>()
.not_modified()
.not_found(),
),
)
// WIP
.route("/api/metrics/bulk", get(data::handler))
// WIP
.route(
"/api/metrics/{metric}/{index}",
"/api/metric/{metric}/{index}",
get(
async |uri: Uri,
headers: HeaderMap,
state: State<AppState>,
Path((metric, index)): Path<(String, Index)>,
Path((metric, index)): Path<(MetricPath, Index)>,
Query(params_opt): Query<ParamsOpt>|
-> Response {
data::handler(
uri,
headers,
Query(Params::from(((index, metric), params_opt))),
state,
)
.await
todo!();
// data::handler(
// uri,
// headers,
// Query(Params::from(((index, metric), params_opt))),
// state,
// )
// .await
},
),
)

View File

View File

@@ -14,15 +14,16 @@ use brk_structs::Health;
use crate::{
VERSION,
api::{chain::ChainRoutes, metrics::ApiMetricsRoutes},
api::{addresses::AddressRoutes, metrics::ApiMetricsRoutes, transactions::TxRoutes},
extended::{HeaderMapExtended, ResponseExtended, TransformResponseExtended},
};
use super::AppState;
mod chain;
mod addresses;
mod metrics;
mod openapi;
mod transactions;
pub use openapi::*;
@@ -32,7 +33,8 @@ pub trait ApiRoutes {
impl ApiRoutes for ApiRouter<AppState> {
fn add_api_routes(self) -> Self {
self.add_chain_routes()
self.add_addresses_routes()
.add_tx_routes()
.add_metrics_routes()
.route("/api/server", get(Redirect::temporary("/api#tag/server")))
.api_route(
@@ -40,10 +42,10 @@ impl ApiRoutes for ApiRouter<AppState> {
get_with(
async || -> Json<&'static str> { Json(VERSION) },
|op| {
op.tag("Server")
op.server_tag()
.summary("API version")
.description("Returns the current version of the API server")
.with_ok_response::<String, _>(|res| res)
.ok_response::<String>()
},
),
)
@@ -58,10 +60,10 @@ impl ApiRoutes for ApiRouter<AppState> {
})
},
|op| {
op.tag("Server")
op.server_tag()
.summary("Health check")
.description("Returns the health status of the API server")
.with_ok_response::<Health, _>(|res| res)
.ok_response::<Health>()
},
),
)

View File

@@ -18,8 +18,7 @@ pub fn create_openapi() -> OpenApi {
let info = Info {
title: "Bitcoin Research Kit".to_string(),
description: Some(
"API for querying Bitcoin blockchain data including addresses, transactions, and chain statistics. This API provides low-level access to indexed blockchain data with advanced analytics capabilities.\n\n\
⚠️ **Early Development**: This API is in very early stages of development. Breaking changes may occur without notice. For a more stable experience, [self-host](/install) or use the [hosting service](/service)."
"API for querying Bitcoin blockchain data including addresses, transactions, and chain statistics. This API provides low-level access to indexed blockchain data with advanced analytics capabilities."
.to_string(),
),
version: format!("v{VERSION}"),
@@ -28,9 +27,17 @@ pub fn create_openapi() -> OpenApi {
let tags = vec![
Tag {
name: "Chain".to_string(),
name: "Addresses".to_string(),
description: Some(
"Explore Bitcoin blockchain data: addresses, transactions, blocks, balances, and UTXOs."
"Explore Bitcoin addresses."
.to_string()
),
..Default::default()
},
Tag {
name: "Blocks".to_string(),
description: Some(
"Explore Bitcoin blocks."
.to_string()
),
..Default::default()
@@ -44,6 +51,14 @@ pub fn create_openapi() -> OpenApi {
),
..Default::default()
},
Tag {
name: "Mining".to_string(),
description: Some(
"Explore mining related endpoints."
.to_string()
),
..Default::default()
},
Tag {
name: "Server".to_string(),
description: Some(
@@ -51,7 +66,15 @@ pub fn create_openapi() -> OpenApi {
.to_string()
),
..Default::default()
},
},
Tag {
name: "Transactions".to_string(),
description: Some(
"Explore Bitcoin transactions."
.to_string()
),
..Default::default()
},
];
OpenApi {

View File

@@ -2,7 +2,8 @@ use aide::axum::{ApiRouter, routing::get_with};
use axum::{
extract::{Path, State},
http::HeaderMap,
response::Response,
response::{Redirect, Response},
routing::get,
};
use brk_structs::{TransactionInfo, TxidPath};
@@ -13,14 +14,17 @@ use crate::{
use super::AppState;
pub trait TransactionsRoutes {
fn add_transactions_routes(self) -> Self;
pub trait TxRoutes {
fn add_tx_routes(self) -> Self;
}
impl TransactionsRoutes for ApiRouter<AppState> {
fn add_transactions_routes(self) -> Self {
self.api_route(
"/api/chain/tx/{txid}",
impl TxRoutes for ApiRouter<AppState> {
fn add_tx_routes(self) -> Self {
self
.route("/api/tx", get(Redirect::temporary("/api/transactions")))
.route("/api/transactions", get(Redirect::temporary("/api#tag/transactions")))
.api_route(
"/api/tx/{txid}",
get_with(
async |
headers: HeaderMap,
@@ -37,16 +41,16 @@ impl TransactionsRoutes for ApiRouter<AppState> {
}
},
|op| op
.tag("Chain")
.transactions_tag()
.summary("Transaction information")
.description(
"Retrieve complete transaction data by transaction ID (txid). Returns the full transaction details including inputs, outputs, and metadata. The transaction data is read directly from the blockchain data files.",
)
.with_ok_response::<TransactionInfo, _>(|res| res)
.with_not_modified()
.with_bad_request()
.with_not_found()
.with_server_error(),
.ok_response::<TransactionInfo>()
.not_modified()
.bad_request()
.not_found()
.server_error(),
),
)
}