diff --git a/shared/src/commitment_tree.rs b/shared/src/commitment_tree.rs new file mode 100644 index 0000000..2d5c164 --- /dev/null +++ b/shared/src/commitment_tree.rs @@ -0,0 +1,13 @@ +use std::sync::LazyLock; + +use namada_sdk::borsh::BorshSerializeExt; +use namada_sdk::masp_primitives::merkle_tree::CommitmentTree; +use namada_sdk::masp_primitives::sapling::Node; + +/// Return an empty serialized [`CommitmentTree`]. +#[inline] +pub fn empty() -> Vec { + static EMPTY_TREE: LazyLock> = + LazyLock::new(|| CommitmentTree::::empty().serialize_to_vec()); + EMPTY_TREE.clone() +} diff --git a/shared/src/lib.rs b/shared/src/lib.rs index 54714cb..baea858 100644 --- a/shared/src/lib.rs +++ b/shared/src/lib.rs @@ -1,5 +1,6 @@ pub mod block; pub mod block_results; +pub mod commitment_tree; pub mod error; pub mod extracted_masp_tx; pub mod header; diff --git a/webserver/src/error/tree.rs b/webserver/src/error/tree.rs index a31c8d5..d58855b 100644 --- a/webserver/src/error/tree.rs +++ b/webserver/src/error/tree.rs @@ -6,8 +6,6 @@ use crate::response::api::ApiErrorResponse; #[derive(Error, Debug)] pub enum TreeError { - #[error("Commitment Tree not found")] - NotFound, #[error("Database error: {0}")] Database(String), } @@ -15,7 +13,6 @@ pub enum TreeError { impl IntoResponse for TreeError { fn into_response(self) -> Response { let status_code = match self { - TreeError::NotFound => StatusCode::NOT_FOUND, TreeError::Database(_) => StatusCode::INTERNAL_SERVER_ERROR, }; diff --git a/webserver/src/error/witness_map.rs b/webserver/src/error/witness_map.rs index e59b576..7e3c556 100644 --- a/webserver/src/error/witness_map.rs +++ b/webserver/src/error/witness_map.rs @@ -6,8 +6,6 @@ use crate::response::api::ApiErrorResponse; #[derive(Error, Debug)] pub enum WitnessMapError { - #[error("WitnessMap not found")] - NotFound, #[error("Database error: {0}")] Database(String), } @@ -15,7 +13,6 @@ pub enum WitnessMapError { impl IntoResponse for WitnessMapError { fn into_response(self) -> Response { let status_code = match self { - WitnessMapError::NotFound => StatusCode::NOT_FOUND, WitnessMapError::Database(_) => StatusCode::INTERNAL_SERVER_ERROR, }; diff --git a/webserver/src/handler/tree.rs b/webserver/src/handler/tree.rs index 862a74a..f07ae85 100644 --- a/webserver/src/handler/tree.rs +++ b/webserver/src/handler/tree.rs @@ -2,6 +2,7 @@ use axum::extract::{Query, State}; use axum::Json; use axum_macros::debug_handler; use axum_trace_id::TraceId; +use shared::commitment_tree::empty as empty_tree; use shared::error::InspectWrap; use crate::dto::tree::TreeQueryParams; @@ -23,12 +24,11 @@ pub async fn get_commitment_tree( TreeError::Database(err.to_string()) })?; - if let Some((commitment_tree, block_height)) = maybe_commitment_tree { - Ok(Json(TreeResponse { - commitment_tree, - block_height, - })) - } else { - Err(TreeError::NotFound) - } + let (commitment_tree, block_height) = maybe_commitment_tree + .unwrap_or_else(|| (empty_tree(), query_params.height)); + + Ok(Json(TreeResponse { + commitment_tree, + block_height, + })) } diff --git a/webserver/src/handler/witness_map.rs b/webserver/src/handler/witness_map.rs index cd4382e..24534df 100644 --- a/webserver/src/handler/witness_map.rs +++ b/webserver/src/handler/witness_map.rs @@ -24,12 +24,11 @@ pub async fn get_witness_map( WitnessMapError::Database(err.to_string()) })?; - if let Some((witnesses, block_height)) = witnesses_and_height { - Ok(Json(WitnessMapResponse::new( - BlockHeight(block_height), - witnesses, - ))) - } else { - Err(WitnessMapError::NotFound) - } + let (witnesses, block_height) = + witnesses_and_height.unwrap_or((Vec::new(), query_params.height)); + + Ok(Json(WitnessMapResponse::new( + BlockHeight(block_height), + witnesses, + ))) } diff --git a/webserver/src/repository/witness_map.rs b/webserver/src/repository/witness_map.rs index b32104d..49d4c2b 100644 --- a/webserver/src/repository/witness_map.rs +++ b/webserver/src/repository/witness_map.rs @@ -1,5 +1,8 @@ use anyhow::Context; -use diesel::{ExpressionMethods, QueryDsl, RunQueryDsl, SelectableHelper}; +use diesel::{ + ExpressionMethods, OptionalExtension, QueryDsl, RunQueryDsl, + SelectableHelper, +}; use orm::schema::witness; use orm::witness::WitnessDb; use shared::error::ContextDbInteractError; @@ -35,17 +38,21 @@ impl WitnessMapRepositoryTrait for WitnessMapRepository { )?; conn.interact(move |conn| { - let closest_height = witness::table + let Some(closest_height) = witness::table .order(abs(witness::dsl::block_height - block_height).asc()) .filter(witness::dsl::block_height.le(block_height)) .select(witness::dsl::block_height) .first(conn) + .optional() .with_context(|| { format!( "Failed to fetch height from the db closest to the \ provided height {block_height}" ) - })?; + })? + else { + return anyhow::Ok((vec![], block_height)); + }; let witnesses = witness::table .filter(witness::dsl::block_height.eq(closest_height))