Block explorer 2 (#566)

* support query block list from explorer
This commit is contained in:
Al Liu 2024-01-31 16:30:48 +08:00 committed by GitHub
parent c6f042b94f
commit ad47dcf228
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 197 additions and 10 deletions

View File

@ -12,6 +12,7 @@ nomos-storage = { path = "../../nomos-services/storage", features = ["sled"] }
nomos-api = { path = "../../nomos-services/api" }
nomos-node = { path = "../nomos-node" }
nomos-core = { path = "../../nomos-core" }
full-replication = { path = "../../nomos-da/full-replication" }
serde = "1.0"
tracing = "0.1"
async-trait = "0.1.73"
@ -19,8 +20,9 @@ axum = "0.6"
hyper = "0.14.27"
tower-http = "0.4"
utoipa = "4.0"
utoipa-swagger-ui = "4.0"
utoipa-swagger-ui = "6.0"
futures = "0.3"
serde_yaml = "0.9.25"
clap = { version = "4.4.6", features = ["derive"] }
eyre = "0.6"
eyre = "0.6"

View File

@ -84,7 +84,12 @@ where
)
.layer(TraceLayer::new_for_http())
// .merge(SwaggerUi::new("/swagger-ui").url("/api-docs/openapi.json", ApiDoc::openapi()))
.route("/blocks", routing::get(store::store_blocks::<T, S>))
.route("/store/blocks", routing::get(store::store_blocks::<T, S>))
.route("/explorer/blocks", routing::get(store::blocks::<T, S>))
.route(
"/explorer/blocks/depth",
routing::get(store::block_depth::<T, S>),
)
.with_state(handle);
Server::bind(&self.settings.address)

View File

@ -4,12 +4,14 @@ use std::hash::Hash;
// crates
use axum::extract::{Query, State};
use axum::response::Response;
use axum::response::{IntoResponse, Response};
use hyper::StatusCode;
use serde::de::DeserializeOwned;
use serde::{Deserialize, Serialize};
// internal
use full_replication::Certificate;
use nomos_api::http::storage;
use nomos_core::block::BlockId;
use nomos_core::block::{Block, BlockId};
use nomos_core::tx::Transaction;
use nomos_node::make_request_and_return_response;
use nomos_storage::backends::StorageSerde;
@ -44,3 +46,182 @@ where
.collect();
make_request_and_return_response!(futures::future::try_join_all(results))
}
#[derive(Deserialize)]
pub(crate) struct BlocksByIdQueryParams {
from: BlockId,
to: Option<BlockId>,
}
pub(crate) async fn blocks<Tx, S>(
State(store): State<OverwatchHandle>,
Query(query): Query<BlocksByIdQueryParams>,
) -> Response
where
Tx: Transaction
+ Clone
+ Debug
+ Eq
+ Hash
+ Serialize
+ DeserializeOwned
+ Send
+ Sync
+ 'static,
<Tx as Transaction>::Hash: std::cmp::Ord + Debug + Send + Sync + 'static,
S: StorageSerde + Send + Sync + 'static,
{
let BlocksByIdQueryParams { from, to } = query;
// get the from block
let from = match storage::block_req::<S, Tx>(&store, from).await {
Ok(from) => match from {
Some(from) => from,
None => {
return IntoResponse::into_response((StatusCode::NOT_FOUND, "from block not found"))
}
},
Err(e) => {
return IntoResponse::into_response((StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))
}
};
// check if to is valid
match to {
Some(to) => match storage::block_req::<S, Tx>(&store, to).await {
Ok(to) => match to {
Some(to) => handle_to::<S, Tx>(store, from, Some(to)).await,
None => IntoResponse::into_response((StatusCode::NOT_FOUND, "to block not found")),
},
Err(e) => {
IntoResponse::into_response((StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))
}
},
None => handle_to::<S, Tx>(store, from, None).await,
}
}
async fn handle_to<S, Tx>(
store: OverwatchHandle,
from: Block<Tx, Certificate>,
to: Option<Block<Tx, Certificate>>,
) -> Response
where
Tx: Transaction
+ Clone
+ Debug
+ Eq
+ Hash
+ Serialize
+ DeserializeOwned
+ Send
+ Sync
+ 'static,
<Tx as Transaction>::Hash: std::cmp::Ord + Debug + Send + Sync + 'static,
S: StorageSerde + Send + Sync + 'static,
{
let mut current = Some(from.header().parent());
let mut blocks = Vec::new();
while let Some(id) = current {
if let Some(to) = &to {
if id == to.header().id {
break;
}
}
let block = match storage::block_req::<S, Tx>(&store, id).await {
Ok(block) => block,
Err(e) => {
return IntoResponse::into_response((
StatusCode::INTERNAL_SERVER_ERROR,
e.to_string(),
))
}
};
match block {
Some(block) => {
current = Some(block.header().parent());
blocks.push(block);
}
None => {
current = None;
}
}
}
IntoResponse::into_response((StatusCode::OK, ::axum::Json(blocks)))
}
#[derive(Deserialize)]
pub(crate) struct BlocksByDepthQueryParams {
from: BlockId,
#[serde(default = "default_depth")]
depth: usize,
}
fn default_depth() -> usize {
500
}
pub(crate) async fn block_depth<Tx, S>(
State(store): State<OverwatchHandle>,
Query(query): Query<BlocksByDepthQueryParams>,
) -> Response
where
Tx: Transaction
+ Clone
+ Debug
+ Eq
+ Hash
+ Serialize
+ DeserializeOwned
+ Send
+ Sync
+ 'static,
<Tx as Transaction>::Hash: std::cmp::Ord + Debug + Send + Sync + 'static,
S: StorageSerde + Send + Sync + 'static,
{
let BlocksByDepthQueryParams { from, depth } = query;
// get the from block
let from = match storage::block_req::<S, Tx>(&store, from).await {
Ok(from) => match from {
Some(from) => from,
None => {
return IntoResponse::into_response((StatusCode::NOT_FOUND, "from block not found"))
}
},
Err(e) => {
return IntoResponse::into_response((StatusCode::INTERNAL_SERVER_ERROR, e.to_string()))
}
};
let mut current = Some(from.header().parent());
let mut blocks = Vec::new();
while blocks.len() < depth {
if let Some(id) = current {
let block = match storage::block_req::<S, Tx>(&store, id).await {
Ok(block) => block,
Err(e) => {
return IntoResponse::into_response((
StatusCode::INTERNAL_SERVER_ERROR,
e.to_string(),
))
}
};
match block {
Some(block) => {
current = Some(block.header().parent());
blocks.push(block);
}
None => {
current = None;
}
}
} else {
break;
}
}
IntoResponse::into_response((StatusCode::OK, ::axum::Json(blocks)))
}

View File

@ -40,7 +40,6 @@ impl StorageTransaction for SledTransaction {
}
/// Sled storage backend
pub struct SledBackend<SerdeOp> {
sled: sled::Db,
_serde_op: PhantomData<SerdeOp>,

View File

@ -136,16 +136,16 @@ impl<Backend: StorageBackend> StorageMsg<Backend> {
impl<Backend: StorageBackend> Debug for StorageMsg<Backend> {
fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
match self {
StorageMsg::Load { key, .. } => {
Self::Load { key, .. } => {
write!(f, "Load {{ {key:?} }}")
}
StorageMsg::Store { key, value } => {
Self::Store { key, value } => {
write!(f, "Store {{ {key:?}, {value:?}}}")
}
StorageMsg::Remove { key, .. } => {
Self::Remove { key, .. } => {
write!(f, "Remove {{ {key:?} }}")
}
StorageMsg::Execute { .. } => write!(f, "Execute transaction"),
Self::Execute { .. } => write!(f, "Execute transaction"),
}
}
}