mirror of
https://github.com/bitcoinresearchkit/brk.git
synced 2026-06-10 06:53:33 -07:00
server: openapi fixes
This commit is contained in:
@@ -7,7 +7,7 @@ use crate::Query;
|
||||
const DEFAULT_BLOCK_COUNT: u32 = 10;
|
||||
|
||||
impl Query {
|
||||
pub fn block(&self, hash: &str) -> Result<BlockInfo> {
|
||||
pub fn block(&self, hash: &BlockHash) -> Result<BlockInfo> {
|
||||
let height = self.height_by_hash(hash)?;
|
||||
self.block_by_height(height)
|
||||
}
|
||||
@@ -58,11 +58,10 @@ impl Query {
|
||||
|
||||
// === Helper methods ===
|
||||
|
||||
pub fn height_by_hash(&self, hash: &str) -> Result<Height> {
|
||||
pub fn height_by_hash(&self, hash: &BlockHash) -> Result<Height> {
|
||||
let indexer = self.indexer();
|
||||
|
||||
let blockhash: BlockHash = hash.parse().map_err(|_| Error::Str("Invalid block hash"))?;
|
||||
let prefix = BlockHashPrefix::from(&blockhash);
|
||||
let prefix = BlockHashPrefix::from(hash);
|
||||
|
||||
indexer
|
||||
.stores
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
use brk_error::{Error, Result};
|
||||
use brk_types::Height;
|
||||
use brk_types::{BlockHash, Height};
|
||||
use vecdb::{AnyVec, GenericStoredVec};
|
||||
|
||||
use crate::Query;
|
||||
|
||||
impl Query {
|
||||
pub fn block_raw(&self, hash: &str) -> Result<Vec<u8>> {
|
||||
pub fn block_raw(&self, hash: &BlockHash) -> Result<Vec<u8>> {
|
||||
let height = self.height_by_hash(hash)?;
|
||||
self.block_raw_by_height(height)
|
||||
}
|
||||
|
||||
@@ -1,11 +1,11 @@
|
||||
use brk_error::Result;
|
||||
use brk_types::{BlockStatus, Height};
|
||||
use brk_types::{BlockHash, BlockStatus, Height};
|
||||
use vecdb::{AnyVec, GenericStoredVec};
|
||||
|
||||
use crate::Query;
|
||||
|
||||
impl Query {
|
||||
pub fn block_status(&self, hash: &str) -> Result<BlockStatus> {
|
||||
pub fn block_status(&self, hash: &BlockHash) -> Result<BlockStatus> {
|
||||
let height = self.height_by_hash(hash)?;
|
||||
self.block_status_by_height(height)
|
||||
}
|
||||
|
||||
@@ -1,24 +1,24 @@
|
||||
use brk_error::{Error, Result};
|
||||
use brk_types::{Height, Transaction, TxIndex, Txid};
|
||||
use brk_types::{BlockHash, Height, Transaction, TxIndex, Txid};
|
||||
use vecdb::{AnyVec, GenericStoredVec, TypedVecIterator};
|
||||
|
||||
use super::BLOCK_TXS_PAGE_SIZE;
|
||||
use crate::Query;
|
||||
|
||||
impl Query {
|
||||
pub fn block_txids(&self, hash: &str) -> Result<Vec<Txid>> {
|
||||
pub fn block_txids(&self, hash: &BlockHash) -> Result<Vec<Txid>> {
|
||||
let height = self.height_by_hash(hash)?;
|
||||
self.block_txids_by_height(height)
|
||||
}
|
||||
|
||||
pub fn block_txs(&self, hash: &str, start_index: usize) -> Result<Vec<Transaction>> {
|
||||
pub fn block_txs(&self, hash: &BlockHash, start_index: TxIndex) -> Result<Vec<Transaction>> {
|
||||
let height = self.height_by_hash(hash)?;
|
||||
self.block_txs_by_height(height, start_index)
|
||||
self.block_txs_by_height(height, start_index.into())
|
||||
}
|
||||
|
||||
pub fn block_txid_at_index(&self, hash: &str, index: usize) -> Result<Txid> {
|
||||
pub fn block_txid_at_index(&self, hash: &BlockHash, index: TxIndex) -> Result<Txid> {
|
||||
let height = self.height_by_hash(hash)?;
|
||||
self.block_txid_at_index_by_height(height, index)
|
||||
self.block_txid_at_index_by_height(height, index.into())
|
||||
}
|
||||
|
||||
// === Helper methods ===
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use std::{io::Cursor, str::FromStr};
|
||||
use std::io::Cursor;
|
||||
|
||||
use bitcoin::{consensus::Decodable, hex::DisplayHex};
|
||||
use brk_error::{Error, Result};
|
||||
use brk_types::{
|
||||
Sats, Transaction, TxIn, TxInIndex, TxIndex, TxOut, TxOutspend, TxStatus, Txid, TxidPath,
|
||||
Sats, Transaction, TxIn, TxInIndex, TxIndex, TxOut, TxOutspend, TxStatus, Txid, TxidParam,
|
||||
TxidPrefix, Vin, Vout, Weight,
|
||||
};
|
||||
use vecdb::{GenericStoredVec, TypedVecIterator};
|
||||
@@ -11,13 +11,7 @@ use vecdb::{GenericStoredVec, TypedVecIterator};
|
||||
use crate::Query;
|
||||
|
||||
impl Query {
|
||||
pub fn transaction(&self, TxidPath { txid }: TxidPath) -> Result<Transaction> {
|
||||
let Ok(txid) = bitcoin::Txid::from_str(&txid) else {
|
||||
return Err(Error::InvalidTxid);
|
||||
};
|
||||
|
||||
let txid = Txid::from(txid);
|
||||
|
||||
pub fn transaction(&self, TxidParam { txid }: TxidParam) -> Result<Transaction> {
|
||||
// First check mempool for unconfirmed transactions
|
||||
if let Some(mempool) = self.mempool()
|
||||
&& let Some(tx_with_hex) = mempool.get_txs().get(&txid)
|
||||
@@ -40,13 +34,7 @@ impl Query {
|
||||
self.transaction_by_index(txindex)
|
||||
}
|
||||
|
||||
pub fn transaction_status(&self, TxidPath { txid }: TxidPath) -> Result<TxStatus> {
|
||||
let Ok(txid) = bitcoin::Txid::from_str(&txid) else {
|
||||
return Err(Error::InvalidTxid);
|
||||
};
|
||||
|
||||
let txid = Txid::from(txid);
|
||||
|
||||
pub fn transaction_status(&self, TxidParam { txid }: TxidParam) -> Result<TxStatus> {
|
||||
// First check mempool for unconfirmed transactions
|
||||
if let Some(mempool) = self.mempool()
|
||||
&& mempool.get_txs().contains_key(&txid)
|
||||
@@ -79,13 +67,7 @@ impl Query {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn transaction_hex(&self, TxidPath { txid }: TxidPath) -> Result<String> {
|
||||
let Ok(txid) = bitcoin::Txid::from_str(&txid) else {
|
||||
return Err(Error::InvalidTxid);
|
||||
};
|
||||
|
||||
let txid = Txid::from(txid);
|
||||
|
||||
pub fn transaction_hex(&self, TxidParam { txid }: TxidParam) -> Result<String> {
|
||||
// First check mempool for unconfirmed transactions
|
||||
if let Some(mempool) = self.mempool()
|
||||
&& let Some(tx_with_hex) = mempool.get_txs().get(&txid)
|
||||
@@ -108,13 +90,7 @@ impl Query {
|
||||
self.transaction_hex_by_index(txindex)
|
||||
}
|
||||
|
||||
pub fn outspend(&self, TxidPath { txid }: TxidPath, vout: Vout) -> Result<TxOutspend> {
|
||||
let Ok(txid) = bitcoin::Txid::from_str(&txid) else {
|
||||
return Err(Error::InvalidTxid);
|
||||
};
|
||||
|
||||
let txid = Txid::from(txid);
|
||||
|
||||
pub fn outspend(&self, TxidParam { txid }: TxidParam, vout: Vout) -> Result<TxOutspend> {
|
||||
// Mempool outputs are unspent in on-chain terms
|
||||
if let Some(mempool) = self.mempool()
|
||||
&& mempool.get_txs().contains_key(&txid)
|
||||
@@ -156,13 +132,7 @@ impl Query {
|
||||
self.outspend_details(txinindex)
|
||||
}
|
||||
|
||||
pub fn outspends(&self, TxidPath { txid }: TxidPath) -> Result<Vec<TxOutspend>> {
|
||||
let Ok(txid) = bitcoin::Txid::from_str(&txid) else {
|
||||
return Err(Error::InvalidTxid);
|
||||
};
|
||||
|
||||
let txid = Txid::from(txid);
|
||||
|
||||
pub fn outspends(&self, TxidParam { txid }: TxidParam) -> Result<Vec<TxOutspend>> {
|
||||
// Mempool outputs are unspent in on-chain terms
|
||||
if let Some(mempool) = self.mempool()
|
||||
&& let Some(tx_with_hex) = mempool.get_txs().get(&txid)
|
||||
|
||||
@@ -5,7 +5,10 @@ use axum::{
|
||||
response::Redirect,
|
||||
routing::get,
|
||||
};
|
||||
use brk_types::{Address, AddressStats, AddressTxidsParam, AddressValidation, Txid, Utxo};
|
||||
use brk_types::{
|
||||
AddressParam, AddressStats, AddressTxidsParam, AddressValidation, Txid, Utxo,
|
||||
ValidateAddressParam,
|
||||
};
|
||||
|
||||
use crate::{CacheStrategy, extended::TransformResponseExtended};
|
||||
|
||||
@@ -24,10 +27,10 @@ impl AddressRoutes for ApiRouter<AppState> {
|
||||
"/api/address/{address}",
|
||||
get_with(async |
|
||||
headers: HeaderMap,
|
||||
Path(address): Path<Address>,
|
||||
Path(path): Path<AddressParam>,
|
||||
State(state): State<AppState>
|
||||
| {
|
||||
state.cached_json(&headers, CacheStrategy::Height, move |q| q.address(address)).await
|
||||
state.cached_json(&headers, CacheStrategy::Height, move |q| q.address(path.address)).await
|
||||
}, |op| op
|
||||
.addresses_tag()
|
||||
.summary("Address information")
|
||||
@@ -43,11 +46,11 @@ impl AddressRoutes for ApiRouter<AppState> {
|
||||
"/api/address/{address}/txs",
|
||||
get_with(async |
|
||||
headers: HeaderMap,
|
||||
Path(address): Path<Address>,
|
||||
Path(path): Path<AddressParam>,
|
||||
Query(params): Query<AddressTxidsParam>,
|
||||
State(state): State<AppState>
|
||||
| {
|
||||
state.cached_json(&headers, CacheStrategy::Height, move |q| q.address_txids(address, params.after_txid, params.limit)).await
|
||||
state.cached_json(&headers, CacheStrategy::Height, move |q| q.address_txids(path.address, params.after_txid, params.limit)).await
|
||||
}, |op| op
|
||||
.addresses_tag()
|
||||
.summary("Address transaction IDs")
|
||||
@@ -63,10 +66,10 @@ impl AddressRoutes for ApiRouter<AppState> {
|
||||
"/api/address/{address}/utxo",
|
||||
get_with(async |
|
||||
headers: HeaderMap,
|
||||
Path(address): Path<Address>,
|
||||
Path(path): Path<AddressParam>,
|
||||
State(state): State<AppState>
|
||||
| {
|
||||
state.cached_json(&headers, CacheStrategy::Height, move |q| q.address_utxos(address)).await
|
||||
state.cached_json(&headers, CacheStrategy::Height, move |q| q.address_utxos(path.address)).await
|
||||
}, |op| op
|
||||
.addresses_tag()
|
||||
.summary("Address UTXOs")
|
||||
@@ -82,11 +85,11 @@ impl AddressRoutes for ApiRouter<AppState> {
|
||||
"/api/address/{address}/txs/mempool",
|
||||
get_with(async |
|
||||
headers: HeaderMap,
|
||||
Path(address): Path<Address>,
|
||||
Path(path): Path<AddressParam>,
|
||||
State(state): State<AppState>
|
||||
| {
|
||||
// Mempool txs for an address - use MaxAge since it's volatile
|
||||
state.cached_json(&headers, CacheStrategy::MaxAge(5), move |q| q.address_mempool_txids(address)).await
|
||||
state.cached_json(&headers, CacheStrategy::MaxAge(5), move |q| q.address_mempool_txids(path.address)).await
|
||||
}, |op| op
|
||||
.addresses_tag()
|
||||
.summary("Address mempool transactions")
|
||||
@@ -101,11 +104,11 @@ impl AddressRoutes for ApiRouter<AppState> {
|
||||
"/api/address/{address}/txs/chain",
|
||||
get_with(async |
|
||||
headers: HeaderMap,
|
||||
Path(address): Path<Address>,
|
||||
Path(path): Path<AddressParam>,
|
||||
Query(params): Query<AddressTxidsParam>,
|
||||
State(state): State<AppState>
|
||||
| {
|
||||
state.cached_json(&headers, CacheStrategy::Height, move |q| q.address_txids(address, params.after_txid, 25)).await
|
||||
state.cached_json(&headers, CacheStrategy::Height, move |q| q.address_txids(path.address, params.after_txid, 25)).await
|
||||
}, |op| op
|
||||
.addresses_tag()
|
||||
.summary("Address confirmed transactions")
|
||||
@@ -121,10 +124,10 @@ impl AddressRoutes for ApiRouter<AppState> {
|
||||
"/api/v1/validate-address/{address}",
|
||||
get_with(async |
|
||||
headers: HeaderMap,
|
||||
Path(address): Path<String>,
|
||||
Path(path): Path<ValidateAddressParam>,
|
||||
State(state): State<AppState>
|
||||
| {
|
||||
state.cached_json(&headers, CacheStrategy::Static, move |_q| Ok(AddressValidation::from_address(&address))).await
|
||||
state.cached_json(&headers, CacheStrategy::Static, move |_q| Ok(AddressValidation::from_address(&path.address))).await
|
||||
}, |op| op
|
||||
.addresses_tag()
|
||||
.summary("Validate address")
|
||||
|
||||
@@ -7,8 +7,8 @@ use axum::{
|
||||
};
|
||||
use brk_query::BLOCK_TXS_PAGE_SIZE;
|
||||
use brk_types::{
|
||||
BlockHashPath, BlockHashStartIndexPath, BlockHashTxIndexPath, BlockInfo, BlockStatus,
|
||||
BlockTimestamp, Height, HeightPath, StartHeightPath, TimestampPath, Transaction, Txid,
|
||||
BlockHashParam, BlockHashStartIndex, BlockHashTxIndex, BlockInfo, BlockStatus, BlockTimestamp,
|
||||
HeightParam, StartHeightParam, TimestampParam, Transaction, Txid,
|
||||
};
|
||||
|
||||
use crate::{CacheStrategy, extended::TransformResponseExtended};
|
||||
@@ -30,7 +30,7 @@ impl BlockRoutes for ApiRouter<AppState> {
|
||||
"/api/block/{hash}",
|
||||
get_with(
|
||||
async |headers: HeaderMap,
|
||||
Path(path): Path<BlockHashPath>,
|
||||
Path(path): Path<BlockHashParam>,
|
||||
State(state): State<AppState>| {
|
||||
state.cached_json(&headers, CacheStrategy::Height, move |q| q.block(&path.hash)).await
|
||||
},
|
||||
@@ -52,7 +52,7 @@ impl BlockRoutes for ApiRouter<AppState> {
|
||||
"/api/block/{hash}/status",
|
||||
get_with(
|
||||
async |headers: HeaderMap,
|
||||
Path(path): Path<BlockHashPath>,
|
||||
Path(path): Path<BlockHashParam>,
|
||||
State(state): State<AppState>| {
|
||||
state.cached_json(&headers, CacheStrategy::Height, move |q| q.block_status(&path.hash)).await
|
||||
},
|
||||
@@ -74,10 +74,9 @@ impl BlockRoutes for ApiRouter<AppState> {
|
||||
"/api/block-height/{height}",
|
||||
get_with(
|
||||
async |headers: HeaderMap,
|
||||
Path(path): Path<HeightPath>,
|
||||
Path(path): Path<HeightParam>,
|
||||
State(state): State<AppState>| {
|
||||
let height = Height::from(path.height);
|
||||
state.cached_json(&headers, CacheStrategy::Height, move |q| q.block_by_height(height)).await
|
||||
state.cached_json(&headers, CacheStrategy::Height, move |q| q.block_by_height(path.height)).await
|
||||
},
|
||||
|op| {
|
||||
op.blocks_tag()
|
||||
@@ -97,10 +96,9 @@ impl BlockRoutes for ApiRouter<AppState> {
|
||||
"/api/blocks/{start_height}",
|
||||
get_with(
|
||||
async |headers: HeaderMap,
|
||||
Path(path): Path<StartHeightPath>,
|
||||
Path(path): Path<StartHeightParam>,
|
||||
State(state): State<AppState>| {
|
||||
let start_height = path.start_height.map(Height::from);
|
||||
state.cached_json(&headers, CacheStrategy::Height, move |q| q.blocks(start_height)).await
|
||||
state.cached_json(&headers, CacheStrategy::Height, move |q| q.blocks(path.start_height)).await
|
||||
},
|
||||
|op| {
|
||||
op.blocks_tag()
|
||||
@@ -119,7 +117,7 @@ impl BlockRoutes for ApiRouter<AppState> {
|
||||
"/api/block/{hash}/txids",
|
||||
get_with(
|
||||
async |headers: HeaderMap,
|
||||
Path(path): Path<BlockHashPath>,
|
||||
Path(path): Path<BlockHashParam>,
|
||||
State(state): State<AppState>| {
|
||||
state.cached_json(&headers, CacheStrategy::Height, move |q| q.block_txids(&path.hash)).await
|
||||
},
|
||||
@@ -141,7 +139,7 @@ impl BlockRoutes for ApiRouter<AppState> {
|
||||
"/api/block/{hash}/txs/{start_index}",
|
||||
get_with(
|
||||
async |headers: HeaderMap,
|
||||
Path(path): Path<BlockHashStartIndexPath>,
|
||||
Path(path): Path<BlockHashStartIndex>,
|
||||
State(state): State<AppState>| {
|
||||
state.cached_json(&headers, CacheStrategy::Height, move |q| q.block_txs(&path.hash, path.start_index)).await
|
||||
},
|
||||
@@ -164,7 +162,7 @@ impl BlockRoutes for ApiRouter<AppState> {
|
||||
"/api/block/{hash}/txid/{index}",
|
||||
get_with(
|
||||
async |headers: HeaderMap,
|
||||
Path(path): Path<BlockHashTxIndexPath>,
|
||||
Path(path): Path<BlockHashTxIndex>,
|
||||
State(state): State<AppState>| {
|
||||
state.cached_text(&headers, CacheStrategy::Height, move |q| q.block_txid_at_index(&path.hash, path.index).map(|t| t.to_string())).await
|
||||
},
|
||||
@@ -186,7 +184,7 @@ impl BlockRoutes for ApiRouter<AppState> {
|
||||
"/api/v1/mining/blocks/timestamp/{timestamp}",
|
||||
get_with(
|
||||
async |headers: HeaderMap,
|
||||
Path(path): Path<TimestampPath>,
|
||||
Path(path): Path<TimestampParam>,
|
||||
State(state): State<AppState>| {
|
||||
state.cached_json(&headers, CacheStrategy::Height, move |q| q.block_by_timestamp(path.timestamp)).await
|
||||
},
|
||||
@@ -206,7 +204,7 @@ impl BlockRoutes for ApiRouter<AppState> {
|
||||
"/api/block/{hash}/raw",
|
||||
get_with(
|
||||
async |headers: HeaderMap,
|
||||
Path(path): Path<BlockHashPath>,
|
||||
Path(path): Path<BlockHashParam>,
|
||||
State(state): State<AppState>| {
|
||||
state.cached_bytes(&headers, CacheStrategy::Height, move |q| q.block_raw(&path.hash)).await
|
||||
},
|
||||
|
||||
@@ -10,7 +10,7 @@ use brk_query::{
|
||||
};
|
||||
use brk_traversable::TreeNode;
|
||||
use brk_types::{
|
||||
Index, IndexInfo, Limit, Metric, MetricCount, MetricData, MetricWithIndex, Metrics,
|
||||
Index, IndexInfo, LimitParam, MetricCount, MetricData, MetricParam, MetricWithIndex, Metrics,
|
||||
};
|
||||
|
||||
use crate::{CacheStrategy, extended::TransformResponseExtended};
|
||||
@@ -109,14 +109,13 @@ impl ApiMetricsRoutes for ApiRouter<AppState> {
|
||||
async |
|
||||
headers: HeaderMap,
|
||||
State(state): State<AppState>,
|
||||
Path(metric): Path<Metric>,
|
||||
Query(limit): Query<Limit>
|
||||
Path(path): Path<MetricParam>,
|
||||
Query(query): Query<LimitParam>
|
||||
| {
|
||||
state.cached_json(&headers, CacheStrategy::Static, move |q| Ok(q.match_metric(&metric, limit))).await
|
||||
state.cached_json(&headers, CacheStrategy::Static, move |q| Ok(q.match_metric(&path.metric, query.limit))).await
|
||||
},
|
||||
|op| op
|
||||
.metrics_tag()
|
||||
// .path_param::<Metric>()
|
||||
.summary("Search metrics")
|
||||
.description("Fuzzy search for metrics by name. Supports partial matches and typos.")
|
||||
.ok_response::<Vec<String>>()
|
||||
@@ -129,13 +128,13 @@ impl ApiMetricsRoutes for ApiRouter<AppState> {
|
||||
async |
|
||||
headers: HeaderMap,
|
||||
State(state): State<AppState>,
|
||||
Path(metric): Path<Metric>
|
||||
Path(path): Path<MetricParam>
|
||||
| {
|
||||
state.cached_json(&headers, CacheStrategy::Static, move |q| {
|
||||
if let Some(indexes) = q.metric_to_indexes(metric.clone()) {
|
||||
if let Some(indexes) = q.metric_to_indexes(path.metric.clone()) {
|
||||
return Ok(indexes.clone())
|
||||
}
|
||||
Err(q.metric_not_found_error(&metric))
|
||||
Err(q.metric_not_found_error(&path.metric))
|
||||
}).await
|
||||
},
|
||||
|op| op
|
||||
|
||||
@@ -6,9 +6,9 @@ use axum::{
|
||||
routing::get,
|
||||
};
|
||||
use brk_types::{
|
||||
BlockCountPath, BlockFeeRatesEntry, BlockFeesEntry, BlockRewardsEntry, BlockSizesWeights,
|
||||
BlockCountParam, BlockFeeRatesEntry, BlockFeesEntry, BlockRewardsEntry, BlockSizesWeights,
|
||||
DifficultyAdjustment, DifficultyAdjustmentEntry, HashrateSummary, PoolDetail, PoolInfo,
|
||||
PoolSlugPath, PoolsSummary, RewardStats, TimePeriod,
|
||||
PoolSlugParam, PoolsSummary, RewardStats, TimePeriodParam,
|
||||
};
|
||||
|
||||
use crate::{CacheStrategy, extended::TransformResponseExtended};
|
||||
@@ -61,8 +61,8 @@ impl MiningRoutes for ApiRouter<AppState> {
|
||||
.api_route(
|
||||
"/api/v1/mining/pools/{time_period}",
|
||||
get_with(
|
||||
async |headers: HeaderMap, Path(time_period): Path<TimePeriod>, State(state): State<AppState>| {
|
||||
state.cached_json(&headers, CacheStrategy::height_with(format!("{:?}", time_period)), move |q| q.mining_pools(time_period)).await
|
||||
async |headers: HeaderMap, Path(path): Path<TimePeriodParam>, State(state): State<AppState>| {
|
||||
state.cached_json(&headers, CacheStrategy::height_with(format!("{:?}", path.time_period)), move |q| q.mining_pools(path.time_period)).await
|
||||
},
|
||||
|op| {
|
||||
op.mining_tag()
|
||||
@@ -77,7 +77,7 @@ impl MiningRoutes for ApiRouter<AppState> {
|
||||
.api_route(
|
||||
"/api/v1/mining/pool/{slug}",
|
||||
get_with(
|
||||
async |headers: HeaderMap, Path(path): Path<PoolSlugPath>, State(state): State<AppState>| {
|
||||
async |headers: HeaderMap, Path(path): Path<PoolSlugParam>, State(state): State<AppState>| {
|
||||
state.cached_json(&headers, CacheStrategy::height_with(path.slug), move |q| q.pool_detail(path.slug)).await
|
||||
},
|
||||
|op| {
|
||||
@@ -110,8 +110,8 @@ impl MiningRoutes for ApiRouter<AppState> {
|
||||
.api_route(
|
||||
"/api/v1/mining/hashrate/{time_period}",
|
||||
get_with(
|
||||
async |headers: HeaderMap, Path(time_period): Path<TimePeriod>, State(state): State<AppState>| {
|
||||
state.cached_json(&headers, CacheStrategy::height_with(format!("hashrate-{:?}", time_period)), move |q| q.hashrate(Some(time_period))).await
|
||||
async |headers: HeaderMap, Path(path): Path<TimePeriodParam>, State(state): State<AppState>| {
|
||||
state.cached_json(&headers, CacheStrategy::height_with(format!("hashrate-{:?}", path.time_period)), move |q| q.hashrate(Some(path.time_period))).await
|
||||
},
|
||||
|op| {
|
||||
op.mining_tag()
|
||||
@@ -142,8 +142,8 @@ impl MiningRoutes for ApiRouter<AppState> {
|
||||
.api_route(
|
||||
"/api/v1/mining/difficulty-adjustments/{time_period}",
|
||||
get_with(
|
||||
async |headers: HeaderMap, Path(time_period): Path<TimePeriod>, State(state): State<AppState>| {
|
||||
state.cached_json(&headers, CacheStrategy::height_with(format!("diff-adj-{:?}", time_period)), move |q| q.difficulty_adjustments(Some(time_period))).await
|
||||
async |headers: HeaderMap, Path(path): Path<TimePeriodParam>, State(state): State<AppState>| {
|
||||
state.cached_json(&headers, CacheStrategy::height_with(format!("diff-adj-{:?}", path.time_period)), move |q| q.difficulty_adjustments(Some(path.time_period))).await
|
||||
},
|
||||
|op| {
|
||||
op.mining_tag()
|
||||
@@ -158,8 +158,8 @@ impl MiningRoutes for ApiRouter<AppState> {
|
||||
.api_route(
|
||||
"/api/v1/mining/blocks/fees/{time_period}",
|
||||
get_with(
|
||||
async |headers: HeaderMap, Path(time_period): Path<TimePeriod>, State(state): State<AppState>| {
|
||||
state.cached_json(&headers, CacheStrategy::height_with(format!("fees-{:?}", time_period)), move |q| q.block_fees(time_period)).await
|
||||
async |headers: HeaderMap, Path(path): Path<TimePeriodParam>, State(state): State<AppState>| {
|
||||
state.cached_json(&headers, CacheStrategy::height_with(format!("fees-{:?}", path.time_period)), move |q| q.block_fees(path.time_period)).await
|
||||
},
|
||||
|op| {
|
||||
op.mining_tag()
|
||||
@@ -174,8 +174,8 @@ impl MiningRoutes for ApiRouter<AppState> {
|
||||
.api_route(
|
||||
"/api/v1/mining/blocks/rewards/{time_period}",
|
||||
get_with(
|
||||
async |headers: HeaderMap, Path(time_period): Path<TimePeriod>, State(state): State<AppState>| {
|
||||
state.cached_json(&headers, CacheStrategy::height_with(format!("rewards-{:?}", time_period)), move |q| q.block_rewards(time_period)).await
|
||||
async |headers: HeaderMap, Path(path): Path<TimePeriodParam>, State(state): State<AppState>| {
|
||||
state.cached_json(&headers, CacheStrategy::height_with(format!("rewards-{:?}", path.time_period)), move |q| q.block_rewards(path.time_period)).await
|
||||
},
|
||||
|op| {
|
||||
op.mining_tag()
|
||||
@@ -190,8 +190,8 @@ impl MiningRoutes for ApiRouter<AppState> {
|
||||
.api_route(
|
||||
"/api/v1/mining/blocks/fee-rates/{time_period}",
|
||||
get_with(
|
||||
async |headers: HeaderMap, Path(time_period): Path<TimePeriod>, State(state): State<AppState>| {
|
||||
state.cached_json(&headers, CacheStrategy::height_with(format!("feerates-{:?}", time_period)), move |q| q.block_fee_rates(time_period)).await
|
||||
async |headers: HeaderMap, Path(path): Path<TimePeriodParam>, State(state): State<AppState>| {
|
||||
state.cached_json(&headers, CacheStrategy::height_with(format!("feerates-{:?}", path.time_period)), move |q| q.block_fee_rates(path.time_period)).await
|
||||
},
|
||||
|op| {
|
||||
op.mining_tag()
|
||||
@@ -206,8 +206,8 @@ impl MiningRoutes for ApiRouter<AppState> {
|
||||
.api_route(
|
||||
"/api/v1/mining/blocks/sizes-weights/{time_period}",
|
||||
get_with(
|
||||
async |headers: HeaderMap, Path(time_period): Path<TimePeriod>, State(state): State<AppState>| {
|
||||
state.cached_json(&headers, CacheStrategy::height_with(format!("sizes-{:?}", time_period)), move |q| q.block_sizes_weights(time_period)).await
|
||||
async |headers: HeaderMap, Path(path): Path<TimePeriodParam>, State(state): State<AppState>| {
|
||||
state.cached_json(&headers, CacheStrategy::height_with(format!("sizes-{:?}", path.time_period)), move |q| q.block_sizes_weights(path.time_period)).await
|
||||
},
|
||||
|op| {
|
||||
op.mining_tag()
|
||||
@@ -222,7 +222,7 @@ impl MiningRoutes for ApiRouter<AppState> {
|
||||
.api_route(
|
||||
"/api/v1/mining/reward-stats/{block_count}",
|
||||
get_with(
|
||||
async |headers: HeaderMap, Path(path): Path<BlockCountPath>, State(state): State<AppState>| {
|
||||
async |headers: HeaderMap, Path(path): Path<BlockCountParam>, State(state): State<AppState>| {
|
||||
state.cached_json(&headers, CacheStrategy::height_with(format!("reward-stats-{}", path.block_count)), move |q| q.reward_stats(path.block_count)).await
|
||||
},
|
||||
|op| {
|
||||
|
||||
@@ -5,7 +5,7 @@ use axum::{
|
||||
response::Redirect,
|
||||
routing::get,
|
||||
};
|
||||
use brk_types::{Transaction, TxOutspend, TxStatus, TxidPath, TxidVoutPath};
|
||||
use brk_types::{Transaction, TxOutspend, TxStatus, TxidParam, TxidVout};
|
||||
|
||||
use crate::{CacheStrategy, extended::TransformResponseExtended};
|
||||
|
||||
@@ -25,7 +25,7 @@ impl TxRoutes for ApiRouter<AppState> {
|
||||
get_with(
|
||||
async |
|
||||
headers: HeaderMap,
|
||||
Path(txid): Path<TxidPath>,
|
||||
Path(txid): Path<TxidParam>,
|
||||
State(state): State<AppState>
|
||||
| {
|
||||
state.cached_json(&headers, CacheStrategy::Height, move |q| q.transaction(txid)).await
|
||||
@@ -48,7 +48,7 @@ impl TxRoutes for ApiRouter<AppState> {
|
||||
get_with(
|
||||
async |
|
||||
headers: HeaderMap,
|
||||
Path(txid): Path<TxidPath>,
|
||||
Path(txid): Path<TxidParam>,
|
||||
State(state): State<AppState>
|
||||
| {
|
||||
state.cached_json(&headers, CacheStrategy::Height, move |q| q.transaction_status(txid)).await
|
||||
@@ -71,7 +71,7 @@ impl TxRoutes for ApiRouter<AppState> {
|
||||
get_with(
|
||||
async |
|
||||
headers: HeaderMap,
|
||||
Path(txid): Path<TxidPath>,
|
||||
Path(txid): Path<TxidParam>,
|
||||
State(state): State<AppState>
|
||||
| {
|
||||
state.cached_text(&headers, CacheStrategy::Height, move |q| q.transaction_hex(txid)).await
|
||||
@@ -94,10 +94,10 @@ impl TxRoutes for ApiRouter<AppState> {
|
||||
get_with(
|
||||
async |
|
||||
headers: HeaderMap,
|
||||
Path(path): Path<TxidVoutPath>,
|
||||
Path(path): Path<TxidVout>,
|
||||
State(state): State<AppState>
|
||||
| {
|
||||
let txid = TxidPath { txid: path.txid };
|
||||
let txid = TxidParam { txid: path.txid };
|
||||
state.cached_json(&headers, CacheStrategy::Height, move |q| q.outspend(txid, path.vout)).await
|
||||
},
|
||||
|op| op
|
||||
@@ -118,7 +118,7 @@ impl TxRoutes for ApiRouter<AppState> {
|
||||
get_with(
|
||||
async |
|
||||
headers: HeaderMap,
|
||||
Path(txid): Path<TxidPath>,
|
||||
Path(txid): Path<TxidParam>,
|
||||
State(state): State<AppState>
|
||||
| {
|
||||
state.cached_json(&headers, CacheStrategy::Height, move |q| q.outspends(txid)).await
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
use std::{borrow::Cow, fmt, str::FromStr};
|
||||
use std::{fmt, str::FromStr};
|
||||
|
||||
use bitcoin::ScriptBuf;
|
||||
use brk_error::Error;
|
||||
use derive_deref::Deref;
|
||||
use schemars::{JsonSchema, Schema, SchemaGenerator, json_schema};
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Deserialize, Serialize, Serializer};
|
||||
|
||||
use crate::AddressBytes;
|
||||
@@ -11,29 +11,15 @@ use crate::AddressBytes;
|
||||
use super::OutputType;
|
||||
|
||||
/// Bitcoin address string
|
||||
#[derive(Debug, Deref, Deserialize)]
|
||||
#[derive(Debug, Deref, Deserialize, JsonSchema)]
|
||||
#[serde(transparent)]
|
||||
#[schemars(
|
||||
example = &"04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f",
|
||||
example = &"1A1zP1eP5QGefi2DMPTfTL5SLmv7DivfNa",
|
||||
example = &"bc1qar0srrr7xfkvy5l643lydnw9re59gtzzwf5mdq"
|
||||
)]
|
||||
pub struct Address(String);
|
||||
|
||||
impl JsonSchema for Address {
|
||||
fn schema_name() -> Cow<'static, str> {
|
||||
Cow::Borrowed("Address")
|
||||
}
|
||||
|
||||
fn json_schema(_: &mut SchemaGenerator) -> Schema {
|
||||
json_schema!({
|
||||
"type": "object",
|
||||
"required": ["address"],
|
||||
"properties": {
|
||||
"address": {
|
||||
"type": "string",
|
||||
"description": "Bitcoin address string",
|
||||
"examples": ["04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f"]
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl fmt::Display for Address {
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
f.write_str(&self.0)
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::Address;
|
||||
|
||||
#[derive(Deserialize, JsonSchema)]
|
||||
pub struct AddressParam {
|
||||
pub address: Address,
|
||||
}
|
||||
@@ -2,8 +2,8 @@ use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Deserialize, JsonSchema)]
|
||||
pub struct BlockCountPath {
|
||||
/// Number of blocks to include in the stats
|
||||
pub struct BlockCountParam {
|
||||
/// Number of recent blocks to include
|
||||
#[schemars(example = 100)]
|
||||
pub block_count: usize,
|
||||
}
|
||||
@@ -4,12 +4,17 @@ use bitcoin::hashes::Hash;
|
||||
use brk_error::Error;
|
||||
use derive_deref::Deref;
|
||||
use schemars::JsonSchema;
|
||||
use serde::{Serialize, Serializer};
|
||||
use serde::{Deserialize, Serialize, Serializer, de};
|
||||
use vecdb::{Bytes, Formattable};
|
||||
|
||||
/// Block hash
|
||||
#[derive(Debug, Deref, Clone, PartialEq, Eq, Bytes, JsonSchema)]
|
||||
#[repr(C)]
|
||||
#[schemars(
|
||||
transparent,
|
||||
with = "String",
|
||||
example = &"000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f"
|
||||
)]
|
||||
pub struct BlockHash([u8; 32]);
|
||||
|
||||
impl TryFrom<&str> for BlockHash {
|
||||
@@ -76,6 +81,16 @@ impl Serialize for BlockHash {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'de> Deserialize<'de> for BlockHash {
|
||||
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
|
||||
where
|
||||
D: serde::Deserializer<'de>,
|
||||
{
|
||||
let s = String::deserialize(deserializer)?;
|
||||
Self::from_str(&s).map_err(de::Error::custom)
|
||||
}
|
||||
}
|
||||
|
||||
impl Formattable for BlockHash {
|
||||
#[inline(always)]
|
||||
fn may_need_escaping() -> bool {
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::BlockHash;
|
||||
|
||||
#[derive(Deserialize, JsonSchema)]
|
||||
pub struct BlockHashParam {
|
||||
pub hash: BlockHash,
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Deserialize, JsonSchema)]
|
||||
pub struct BlockHashPath {
|
||||
/// Bitcoin block hash
|
||||
#[schemars(example = &"000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f")]
|
||||
pub hash: String,
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::{BlockHash, TxIndex};
|
||||
|
||||
#[derive(Deserialize, JsonSchema)]
|
||||
pub struct BlockHashStartIndex {
|
||||
/// Bitcoin block hash
|
||||
pub hash: BlockHash,
|
||||
|
||||
/// Starting transaction index within the block (0-based)
|
||||
#[schemars(example = 0)]
|
||||
pub start_index: TxIndex,
|
||||
}
|
||||
@@ -1,13 +0,0 @@
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Deserialize, JsonSchema)]
|
||||
pub struct BlockHashStartIndexPath {
|
||||
/// Bitcoin block hash
|
||||
#[schemars(example = &"000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f")]
|
||||
pub hash: String,
|
||||
|
||||
/// Starting transaction index (0-based)
|
||||
#[schemars(example = 0)]
|
||||
pub start_index: usize,
|
||||
}
|
||||
+5
-4
@@ -1,13 +1,14 @@
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::{BlockHash, TxIndex};
|
||||
|
||||
#[derive(Deserialize, JsonSchema)]
|
||||
pub struct BlockHashTxIndexPath {
|
||||
pub struct BlockHashTxIndex {
|
||||
/// Bitcoin block hash
|
||||
#[schemars(example = &"000000000019d6689c085ae165831e934ff763ae46a2a6c172b3f1b60a8ce26f")]
|
||||
pub hash: String,
|
||||
pub hash: BlockHash,
|
||||
|
||||
/// Transaction index within the block (0-based)
|
||||
#[schemars(example = 0)]
|
||||
pub index: usize,
|
||||
pub index: TxIndex,
|
||||
}
|
||||
@@ -30,6 +30,7 @@ use super::StoredU64;
|
||||
JsonSchema,
|
||||
Hash,
|
||||
)]
|
||||
#[schemars(example = 0, example = 210_000, example = 420_000, example = 840_000)]
|
||||
pub struct Height(u32);
|
||||
|
||||
impl Height {
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::Height;
|
||||
|
||||
#[derive(Deserialize, JsonSchema)]
|
||||
pub struct HeightParam {
|
||||
pub height: Height,
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Deserialize, JsonSchema)]
|
||||
pub struct HeightPath {
|
||||
/// Bitcoin block height
|
||||
#[schemars(example = 0)]
|
||||
pub height: u32,
|
||||
}
|
||||
+30
-22
@@ -9,6 +9,7 @@ mod addresshash;
|
||||
mod addressindexoutpoint;
|
||||
mod addressindextxindex;
|
||||
mod addressmempoolstats;
|
||||
mod addressparam;
|
||||
mod addressstats;
|
||||
mod addresstxidsparam;
|
||||
mod addressvalidation;
|
||||
@@ -17,14 +18,14 @@ mod bitcoin;
|
||||
mod blkmetadata;
|
||||
mod blkposition;
|
||||
mod block;
|
||||
mod blockcountpath;
|
||||
mod blockcountparam;
|
||||
mod blockfeesentry;
|
||||
mod blockferatesentry;
|
||||
mod blockhash;
|
||||
mod blockhashpath;
|
||||
mod blockhashparam;
|
||||
mod blockhashprefix;
|
||||
mod blockhashstartindexpath;
|
||||
mod blockhashtxindexpath;
|
||||
mod blockhashstartindex;
|
||||
mod blockhashtxindex;
|
||||
mod blockinfo;
|
||||
mod blockrewardsentry;
|
||||
mod blocksizeentry;
|
||||
@@ -56,10 +57,11 @@ mod hashrateentry;
|
||||
mod hashratesummary;
|
||||
mod health;
|
||||
mod height;
|
||||
mod heightpath;
|
||||
mod heightparam;
|
||||
mod index;
|
||||
mod indexinfo;
|
||||
mod limit;
|
||||
mod limitparam;
|
||||
mod loadedaddressdata;
|
||||
mod loadedaddressindex;
|
||||
mod mempoolblock;
|
||||
@@ -67,6 +69,7 @@ mod mempoolentryinfo;
|
||||
mod mempoolinfo;
|
||||
mod metric;
|
||||
mod metriccount;
|
||||
mod metricparam;
|
||||
mod metricdata;
|
||||
mod metrics;
|
||||
mod metricselection;
|
||||
@@ -102,7 +105,7 @@ mod pooldetail;
|
||||
mod poolinfo;
|
||||
mod pools;
|
||||
mod poolslug;
|
||||
mod poolslugpath;
|
||||
mod poolslugparam;
|
||||
mod poolssummary;
|
||||
mod poolstats;
|
||||
mod quarterindex;
|
||||
@@ -111,7 +114,7 @@ mod recommendedfees;
|
||||
mod rewardstats;
|
||||
mod sats;
|
||||
mod semesterindex;
|
||||
mod startheightpath;
|
||||
mod startheightparam;
|
||||
mod stored_bool;
|
||||
mod stored_f32;
|
||||
mod stored_f64;
|
||||
@@ -122,15 +125,15 @@ mod stored_u32;
|
||||
mod stored_u64;
|
||||
mod stored_u8;
|
||||
mod timeperiod;
|
||||
mod timeperiodpath;
|
||||
mod timeperiodparam;
|
||||
mod timestamp;
|
||||
mod timestamppath;
|
||||
mod timestampparam;
|
||||
mod treenode;
|
||||
mod tx;
|
||||
mod txid;
|
||||
mod txidpath;
|
||||
mod txidparam;
|
||||
mod txidprefix;
|
||||
mod txidvoutpath;
|
||||
mod txidvout;
|
||||
mod txin;
|
||||
mod txindex;
|
||||
mod txinindex;
|
||||
@@ -144,6 +147,7 @@ mod typeindex;
|
||||
mod unit;
|
||||
mod unknownoutputindex;
|
||||
mod utxo;
|
||||
mod validateaddressparam;
|
||||
mod vin;
|
||||
mod vout;
|
||||
mod vsize;
|
||||
@@ -158,6 +162,7 @@ pub use addresshash::*;
|
||||
pub use addressindexoutpoint::*;
|
||||
pub use addressindextxindex::*;
|
||||
pub use addressmempoolstats::*;
|
||||
pub use addressparam::*;
|
||||
pub use addressstats::*;
|
||||
pub use addresstxidsparam::*;
|
||||
pub use addressvalidation::*;
|
||||
@@ -166,14 +171,14 @@ pub use bitcoin::*;
|
||||
pub use blkmetadata::*;
|
||||
pub use blkposition::*;
|
||||
pub use block::*;
|
||||
pub use blockcountpath::*;
|
||||
pub use blockcountparam::*;
|
||||
pub use blockfeesentry::*;
|
||||
pub use blockferatesentry::*;
|
||||
pub use blockhash::*;
|
||||
pub use blockhashpath::*;
|
||||
pub use blockhashparam::*;
|
||||
pub use blockhashprefix::*;
|
||||
pub use blockhashstartindexpath::*;
|
||||
pub use blockhashtxindexpath::*;
|
||||
pub use blockhashstartindex::*;
|
||||
pub use blockhashtxindex::*;
|
||||
pub use blockinfo::*;
|
||||
pub use blockrewardsentry::*;
|
||||
pub use blocksizeentry::*;
|
||||
@@ -205,10 +210,11 @@ pub use hashrateentry::*;
|
||||
pub use hashratesummary::*;
|
||||
pub use health::*;
|
||||
pub use height::*;
|
||||
pub use heightpath::*;
|
||||
pub use heightparam::*;
|
||||
pub use index::*;
|
||||
pub use indexinfo::*;
|
||||
pub use limit::*;
|
||||
pub use limitparam::*;
|
||||
pub use loadedaddressdata::*;
|
||||
pub use loadedaddressindex::*;
|
||||
pub use mempoolblock::*;
|
||||
@@ -216,6 +222,7 @@ pub use mempoolentryinfo::*;
|
||||
pub use mempoolinfo::*;
|
||||
pub use metric::*;
|
||||
pub use metriccount::*;
|
||||
pub use metricparam::*;
|
||||
pub use metricdata::*;
|
||||
pub use metrics::*;
|
||||
pub use metricselection::*;
|
||||
@@ -251,7 +258,7 @@ pub use pooldetail::*;
|
||||
pub use poolinfo::*;
|
||||
pub use pools::*;
|
||||
pub use poolslug::*;
|
||||
pub use poolslugpath::*;
|
||||
pub use poolslugparam::*;
|
||||
pub use poolssummary::*;
|
||||
pub use poolstats::*;
|
||||
pub use quarterindex::*;
|
||||
@@ -260,7 +267,7 @@ pub use recommendedfees::*;
|
||||
pub use rewardstats::*;
|
||||
pub use sats::*;
|
||||
pub use semesterindex::*;
|
||||
pub use startheightpath::*;
|
||||
pub use startheightparam::*;
|
||||
pub use stored_bool::*;
|
||||
pub use stored_f32::*;
|
||||
pub use stored_f64::*;
|
||||
@@ -271,15 +278,15 @@ pub use stored_u16::*;
|
||||
pub use stored_u32::*;
|
||||
pub use stored_u64::*;
|
||||
pub use timeperiod::*;
|
||||
pub use timeperiodpath::*;
|
||||
pub use timeperiodparam::*;
|
||||
pub use timestamp::*;
|
||||
pub use timestamppath::*;
|
||||
pub use timestampparam::*;
|
||||
pub use treenode::*;
|
||||
pub use tx::*;
|
||||
pub use txid::*;
|
||||
pub use txidpath::*;
|
||||
pub use txidparam::*;
|
||||
pub use txidprefix::*;
|
||||
pub use txidvoutpath::*;
|
||||
pub use txidvout::*;
|
||||
pub use txin::*;
|
||||
pub use txindex::*;
|
||||
pub use txinindex::*;
|
||||
@@ -293,6 +300,7 @@ pub use typeindex::*;
|
||||
pub use unit::*;
|
||||
pub use unknownoutputindex::*;
|
||||
pub use utxo::*;
|
||||
pub use validateaddressparam::*;
|
||||
pub use vin::*;
|
||||
pub use vout::*;
|
||||
pub use vsize::*;
|
||||
|
||||
@@ -1,12 +1,11 @@
|
||||
use std::borrow::Cow;
|
||||
|
||||
use derive_deref::Deref;
|
||||
use schemars::{JsonSchema, Schema, SchemaGenerator, json_schema};
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
|
||||
/// Maximum number of results to return. Defaults to 100 if not specified.
|
||||
#[derive(Debug, Deref, Deserialize)]
|
||||
#[serde(default = "default_search_limit")]
|
||||
#[derive(Debug, Deref, Deserialize, JsonSchema)]
|
||||
#[serde(transparent)]
|
||||
#[schemars(default, example = 1, example = 10, example = 100)]
|
||||
pub struct Limit(usize);
|
||||
|
||||
impl Limit {
|
||||
@@ -14,26 +13,8 @@ impl Limit {
|
||||
pub const DEFAULT: Self = Self(100);
|
||||
}
|
||||
|
||||
fn default_search_limit() -> Limit {
|
||||
Limit::DEFAULT
|
||||
}
|
||||
|
||||
impl JsonSchema for Limit {
|
||||
fn schema_name() -> Cow<'static, str> {
|
||||
Cow::Borrowed("Limit")
|
||||
}
|
||||
|
||||
fn json_schema(_: &mut SchemaGenerator) -> Schema {
|
||||
json_schema!({
|
||||
"type": "object",
|
||||
"properties": {
|
||||
"limit": {
|
||||
"type": "integer",
|
||||
"description": "Maximum number of results to return. Defaults to 100 if not specified.",
|
||||
"default": 100,
|
||||
"examples": [1, 10, 100, 1000, 10000, 100000]
|
||||
}
|
||||
}
|
||||
})
|
||||
impl Default for Limit {
|
||||
fn default() -> Self {
|
||||
Self::DEFAULT
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::Limit;
|
||||
|
||||
#[derive(Deserialize, JsonSchema)]
|
||||
pub struct LimitParam {
|
||||
#[serde(default)]
|
||||
pub limit: Limit,
|
||||
}
|
||||
@@ -1,12 +1,18 @@
|
||||
use std::{borrow::Cow, fmt::Display};
|
||||
use std::fmt::Display;
|
||||
|
||||
use derive_deref::Deref;
|
||||
use schemars::{JsonSchema, Schema, SchemaGenerator, json_schema};
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
|
||||
/// Metric name
|
||||
#[derive(Debug, Clone, Deref, Deserialize)]
|
||||
#[derive(Debug, Clone, Deref, Deserialize, JsonSchema)]
|
||||
#[serde(transparent)]
|
||||
#[schemars(
|
||||
with = "String",
|
||||
example = &"price_close",
|
||||
example = &"market_cap",
|
||||
example = &"realized_price"
|
||||
)]
|
||||
pub struct Metric(String);
|
||||
|
||||
impl From<String> for Metric {
|
||||
@@ -28,17 +34,3 @@ impl Display for Metric {
|
||||
write!(f, "{}", self.0)
|
||||
}
|
||||
}
|
||||
|
||||
impl JsonSchema for Metric {
|
||||
fn schema_name() -> Cow<'static, str> {
|
||||
Cow::Borrowed("Metric")
|
||||
}
|
||||
|
||||
fn json_schema(_: &mut SchemaGenerator) -> Schema {
|
||||
json_schema!({
|
||||
"type": "string",
|
||||
"description": "Metric name",
|
||||
"examples": ["price_close", "market_cap", "realized_price"]
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::Metric;
|
||||
|
||||
#[derive(Deserialize, JsonSchema)]
|
||||
pub struct MetricParam {
|
||||
pub metric: Metric,
|
||||
}
|
||||
@@ -6,9 +6,14 @@ use serde::Deserialize;
|
||||
|
||||
use super::Metric;
|
||||
|
||||
/// A list of metrics
|
||||
/// Comma-separated list of metric names
|
||||
#[derive(Debug, Deref, JsonSchema)]
|
||||
#[schemars(transparent)]
|
||||
#[schemars(
|
||||
with = "String",
|
||||
example = &"price_close",
|
||||
example = &"price_close,market_cap",
|
||||
example = &"realized_price,nvt_ratio,mvrv"
|
||||
)]
|
||||
pub struct Metrics(Vec<Metric>);
|
||||
|
||||
const MAX_VECS: usize = 32;
|
||||
|
||||
@@ -5,6 +5,9 @@ use crate::{Index, Metric};
|
||||
|
||||
#[derive(Deserialize, JsonSchema)]
|
||||
pub struct MetricWithIndex {
|
||||
/// Metric name
|
||||
pub metric: Metric,
|
||||
|
||||
/// Aggregation index
|
||||
pub index: Index,
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ use serde::{Deserialize, Serialize};
|
||||
pub struct Pagination {
|
||||
/// Pagination index
|
||||
#[serde(default, alias = "p")]
|
||||
#[schemars(example = 0, example = 1, example = 2)]
|
||||
pub page: Option<usize>,
|
||||
}
|
||||
|
||||
|
||||
@@ -3,9 +3,7 @@ use serde::Deserialize;
|
||||
|
||||
use super::PoolSlug;
|
||||
|
||||
/// Path parameter for pool detail endpoint
|
||||
#[derive(Deserialize, JsonSchema)]
|
||||
pub struct PoolSlugPath {
|
||||
/// Pool slug (e.g., "foundryusa", "f2pool", "antpool")
|
||||
pub struct PoolSlugParam {
|
||||
pub slug: PoolSlug,
|
||||
}
|
||||
@@ -1,9 +1,11 @@
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::Height;
|
||||
|
||||
#[derive(Deserialize, JsonSchema)]
|
||||
pub struct StartHeightPath {
|
||||
pub struct StartHeightParam {
|
||||
/// Starting block height (optional, defaults to latest)
|
||||
#[schemars(example = 800000)]
|
||||
pub start_height: Option<u32>,
|
||||
pub start_height: Option<Height>,
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
|
||||
use super::TimePeriod;
|
||||
|
||||
#[derive(Deserialize, JsonSchema)]
|
||||
pub struct TimePeriodParam {
|
||||
pub time_period: TimePeriod,
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
|
||||
use super::TimePeriod;
|
||||
|
||||
/// Path parameter for mining pool statistics time period
|
||||
#[derive(Deserialize, JsonSchema)]
|
||||
pub struct TimePeriodPath {
|
||||
/// Time period for statistics.
|
||||
/// Valid values: 24h, 3d, 1w, 1m, 3m, 6m, 1y, 2y, 3y
|
||||
pub time_period: TimePeriod,
|
||||
}
|
||||
@@ -8,7 +8,7 @@ use vecdb::{CheckedSub, Formattable, Pco};
|
||||
|
||||
use super::Date;
|
||||
|
||||
/// Timestamp
|
||||
/// UNIX timestamp in seconds
|
||||
#[derive(
|
||||
Debug,
|
||||
Default,
|
||||
@@ -24,6 +24,7 @@ use super::Date;
|
||||
Pco,
|
||||
JsonSchema,
|
||||
)]
|
||||
#[schemars(example = 1672531200)]
|
||||
pub struct Timestamp(u32);
|
||||
|
||||
pub const ONE_HOUR_IN_SEC: u32 = 60 * 60;
|
||||
|
||||
@@ -4,8 +4,6 @@ use serde::Deserialize;
|
||||
use crate::Timestamp;
|
||||
|
||||
#[derive(Deserialize, JsonSchema)]
|
||||
pub struct TimestampPath {
|
||||
/// UNIX timestamp in seconds
|
||||
#[schemars(example = 1672531200)]
|
||||
pub struct TimestampParam {
|
||||
pub timestamp: Timestamp,
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::Txid;
|
||||
|
||||
#[derive(Deserialize, JsonSchema)]
|
||||
pub struct TxidParam {
|
||||
pub txid: Txid,
|
||||
}
|
||||
@@ -1,9 +0,0 @@
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Deserialize, JsonSchema)]
|
||||
pub struct TxidPath {
|
||||
/// Bitcoin transaction id
|
||||
#[schemars(example = &"4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b")]
|
||||
pub txid: String,
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::{Txid, Vout};
|
||||
|
||||
#[derive(Deserialize, JsonSchema)]
|
||||
pub struct TxidVout {
|
||||
pub txid: Txid,
|
||||
pub vout: Vout,
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
|
||||
use crate::Vout;
|
||||
|
||||
#[derive(Deserialize, JsonSchema)]
|
||||
pub struct TxidVoutPath {
|
||||
/// Bitcoin transaction id
|
||||
#[schemars(example = &"4a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33b")]
|
||||
pub txid: String,
|
||||
|
||||
/// Output index
|
||||
#[schemars(example = 0)]
|
||||
pub vout: Vout,
|
||||
}
|
||||
@@ -3,7 +3,7 @@ use std::ops::{Add, AddAssign};
|
||||
use byteview::ByteView;
|
||||
use derive_deref::{Deref, DerefMut};
|
||||
use schemars::JsonSchema;
|
||||
use serde::Serialize;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use vecdb::{CheckedSub, Formattable, Pco, PrintableIndex};
|
||||
|
||||
use super::StoredU32;
|
||||
@@ -20,6 +20,7 @@ use super::StoredU32;
|
||||
DerefMut,
|
||||
Default,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
Pco,
|
||||
JsonSchema,
|
||||
Hash,
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
use schemars::JsonSchema;
|
||||
use serde::Deserialize;
|
||||
|
||||
#[derive(Deserialize, JsonSchema)]
|
||||
pub struct ValidateAddressParam {
|
||||
/// Bitcoin address to validate (can be any string)
|
||||
pub address: String,
|
||||
}
|
||||
@@ -4,6 +4,7 @@ use serde::Serialize;
|
||||
|
||||
/// Input index in the spending transaction
|
||||
#[derive(Debug, Deref, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Serialize, JsonSchema)]
|
||||
#[schemars(example = 0)]
|
||||
pub struct Vin(u16);
|
||||
|
||||
impl Vin {
|
||||
|
||||
@@ -20,6 +20,7 @@ use vecdb::{Bytes, Formattable};
|
||||
Bytes,
|
||||
Hash,
|
||||
)]
|
||||
#[schemars(example = 0)]
|
||||
pub struct Vout(u16);
|
||||
|
||||
impl Vout {
|
||||
|
||||
Reference in New Issue
Block a user