Skip to content

Commit ef9302a

Browse files
committed
feat: add epochs/{number}/blocks endpoints using chain_store module
1 parent a8a36b4 commit ef9302a

File tree

3 files changed

+124
-5
lines changed

3 files changed

+124
-5
lines changed

common/src/queries/blocks.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,10 @@ pub enum BlocksStateQuery {
6666
GetBlockHashes {
6767
block_numbers: Vec<u64>,
6868
},
69+
GetBlockHashesByNumberRange {
70+
min_number: u64,
71+
max_number: u64,
72+
},
6973
GetTransactionHashes {
7074
tx_ids: Vec<TxIdentifier>,
7175
},
@@ -94,6 +98,7 @@ pub enum BlocksStateQueryResponse {
9498
BlockTransactionsCBOR(BlockTransactionsCBOR),
9599
BlockInvolvedAddresses(BlockInvolvedAddresses),
96100
BlockHashes(BlockHashes),
101+
BlockHashesByNumberRange(Vec<BlockHash>),
97102
TransactionHashes(TransactionHashes),
98103
UTxOHashes(UTxOHashes),
99104
Error(QueryError),

modules/chain_store/src/chain_store.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -344,6 +344,26 @@ impl ChainStore {
344344
block_hashes,
345345
}))
346346
}
347+
BlocksStateQuery::GetBlockHashesByNumberRange {
348+
min_number,
349+
max_number,
350+
} => {
351+
if *max_number < *min_number {
352+
return Ok(BlocksStateQueryResponse::Error(
353+
QueryError::invalid_request("Invalid number range"),
354+
));
355+
}
356+
let mut block_hashes = Vec::new();
357+
let blocks = store.get_blocks_by_number_range(*min_number, *max_number)?;
358+
for block in blocks {
359+
if let Ok(hash) = Self::get_block_hash(&block) {
360+
block_hashes.push(hash);
361+
}
362+
}
363+
Ok(BlocksStateQueryResponse::BlockHashesByNumberRange(
364+
block_hashes,
365+
))
366+
}
347367
BlocksStateQuery::GetTransactionHashes { tx_ids } => {
348368
let mut block_ids: HashMap<_, Vec<_>> = HashMap::new();
349369
for tx_id in tx_ids {

modules/rest_blockfrost/src/handlers/epochs.rs

Lines changed: 99 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,10 @@ use crate::{
44
EpochActivityRest, ProtocolParamsRest, SPDDByEpochAndPoolItemRest, SPDDByEpochItemRest,
55
},
66
};
7-
use acropolis_common::queries::errors::QueryError;
7+
use acropolis_common::queries::{
8+
blocks::{BlocksStateQuery, BlocksStateQueryResponse},
9+
errors::QueryError,
10+
};
811
use acropolis_common::rest_error::RESTError;
912
use acropolis_common::serialization::Bech32Conversion;
1013
use acropolis_common::{
@@ -501,11 +504,102 @@ pub async fn handle_epoch_pool_stakes_blockfrost(
501504
}
502505

503506
pub async fn handle_epoch_total_blocks_blockfrost(
504-
_context: Arc<Context<Message>>,
505-
_params: Vec<String>,
506-
_handlers_config: Arc<HandlersConfig>,
507+
context: Arc<Context<Message>>,
508+
params: Vec<String>,
509+
handlers_config: Arc<HandlersConfig>,
507510
) -> Result<RESTResponse, RESTError> {
508-
Err(RESTError::not_implemented("Epoch total blocks endpoint"))
511+
if params.len() != 1 {
512+
return Err(RESTError::BadRequest(
513+
"Expected one parameter: an epoch number".to_string(),
514+
));
515+
}
516+
let param = &params[0];
517+
518+
let epoch_number = param
519+
.parse::<u64>()
520+
.map_err(|_| RESTError::invalid_param("epoch", "invalid epoch number"))?;
521+
522+
let latest_epoch_msg = Arc::new(Message::StateQuery(StateQuery::Epochs(
523+
EpochsStateQuery::GetLatestEpoch,
524+
)));
525+
let latest_epoch = query_state(
526+
&context,
527+
&handlers_config.epochs_query_topic,
528+
latest_epoch_msg,
529+
|message| match message {
530+
Message::StateQueryResponse(StateQueryResponse::Epochs(
531+
EpochsStateQueryResponse::LatestEpoch(res),
532+
)) => Ok(res.epoch),
533+
Message::StateQueryResponse(StateQueryResponse::Epochs(
534+
EpochsStateQueryResponse::Error(e),
535+
)) => Err(e),
536+
_ => Err(QueryError::internal_error(
537+
"Unexpected message type while retrieving latest epoch",
538+
)),
539+
},
540+
)
541+
.await?;
542+
543+
if epoch_number > latest_epoch.epoch {
544+
return Err(RESTError::not_found("Epoch not found"));
545+
}
546+
547+
let (first_block_height, last_block_height) = if epoch_number == latest_epoch.epoch {
548+
(
549+
latest_epoch.first_block_height,
550+
latest_epoch.last_block_height,
551+
)
552+
} else {
553+
// Query from historical epochs state
554+
let epoch_info_msg = Arc::new(Message::StateQuery(StateQuery::Epochs(
555+
EpochsStateQuery::GetEpochInfo { epoch_number },
556+
)));
557+
let epoch_info = query_state(
558+
&context,
559+
&handlers_config.epochs_query_topic,
560+
epoch_info_msg,
561+
|message| match message {
562+
Message::StateQueryResponse(StateQueryResponse::Epochs(
563+
EpochsStateQueryResponse::EpochInfo(res),
564+
)) => Ok(res.epoch),
565+
Message::StateQueryResponse(StateQueryResponse::Epochs(
566+
EpochsStateQueryResponse::Error(e),
567+
)) => Err(e),
568+
_ => Err(QueryError::internal_error(
569+
"Unexpected message type while retrieving epoch info",
570+
)),
571+
},
572+
)
573+
.await?;
574+
(epoch_info.first_block_height, epoch_info.last_block_height)
575+
};
576+
577+
// Query all blocks hashes from chain_store
578+
// using first_block_height and last_block_height
579+
let block_hashes_msg = Arc::new(Message::StateQuery(StateQuery::Blocks(
580+
BlocksStateQuery::GetBlockHashesByNumberRange {
581+
min_number: first_block_height,
582+
max_number: last_block_height,
583+
},
584+
)));
585+
let block_hashes = query_state(
586+
&context,
587+
&handlers_config.blocks_query_topic,
588+
block_hashes_msg,
589+
|message| match message {
590+
Message::StateQueryResponse(StateQueryResponse::Blocks(
591+
BlocksStateQueryResponse::BlockHashesByNumberRange(block_hashes),
592+
)) => Ok(block_hashes),
593+
Message::StateQueryResponse(StateQueryResponse::Blocks(
594+
BlocksStateQueryResponse::Error(e),
595+
)) => Err(e),
596+
_ => Err(QueryError::internal_error("Unexpected message type")),
597+
},
598+
)
599+
.await?;
600+
601+
let json = serde_json::to_string_pretty(&block_hashes)?;
602+
Ok(RESTResponse::with_json(200, &json))
509603
}
510604

511605
pub async fn handle_epoch_pool_blocks_blockfrost(

0 commit comments

Comments
 (0)