warg_server/api/v1/
proof.rs1use super::{Json, RegistryHeader};
2use crate::services::{CoreService, CoreServiceError};
3use axum::{
4 debug_handler, extract::State, http::StatusCode, response::IntoResponse, routing::post, Router,
5};
6use warg_api::v1::proof::{
7 ConsistencyRequest, ConsistencyResponse, InclusionRequest, InclusionResponse, ProofError,
8};
9use warg_protocol::registry::{RegistryIndex, RegistryLen};
10
11#[derive(Clone)]
12pub struct Config {
13 core: CoreService,
14}
15
16impl Config {
17 pub fn new(core: CoreService) -> Self {
18 Self { core }
19 }
20
21 pub fn into_router(self) -> Router {
22 Router::new()
23 .route("/consistency", post(prove_consistency))
24 .route("/inclusion", post(prove_inclusion))
25 .with_state(self)
26 }
27}
28
29struct ProofApiError(ProofError);
30
31impl From<CoreServiceError> for ProofApiError {
32 fn from(value: CoreServiceError) -> Self {
33 Self(match value {
34 CoreServiceError::CheckpointNotFound(log_length) => {
35 ProofError::CheckpointNotFound(log_length)
36 }
37 CoreServiceError::LeafNotFound(leaf) => ProofError::LeafNotFound(leaf),
38 CoreServiceError::BundleFailure(e) => ProofError::BundleFailure(e.to_string()),
39 CoreServiceError::PackageNotIncluded(id) => ProofError::PackageLogNotIncluded(id),
40 CoreServiceError::IncorrectProof { root, found } => {
41 ProofError::IncorrectProof { root, found }
42 }
43 other => {
44 tracing::error!("Unhandled CoreServiceError: {other:?}");
45 ProofError::Message {
46 status: 500,
47 message: "Internal service error".to_string(),
48 }
49 }
50 })
51 }
52}
53
54impl IntoResponse for ProofApiError {
55 fn into_response(self) -> axum::response::Response {
56 (StatusCode::from_u16(self.0.status()).unwrap(), Json(self.0)).into_response()
57 }
58}
59
60#[debug_handler]
61async fn prove_consistency(
62 State(config): State<Config>,
63 RegistryHeader(_registry_header): RegistryHeader,
64 Json(body): Json<ConsistencyRequest>,
65) -> Result<Json<ConsistencyResponse>, ProofApiError> {
66 let bundle = config
67 .core
68 .log_consistency_proof(body.from as RegistryLen, body.to as RegistryLen)
69 .await?;
70
71 Ok(Json(ConsistencyResponse {
72 proof: bundle.encode(),
73 }))
74}
75
76#[debug_handler]
77async fn prove_inclusion(
78 State(config): State<Config>,
79 RegistryHeader(_registry_header): RegistryHeader,
80 Json(body): Json<InclusionRequest>,
81) -> Result<Json<InclusionResponse>, ProofApiError> {
82 let log_length = body.log_length as RegistryLen;
83 let leafs = body
84 .leafs
85 .into_iter()
86 .map(|index| index as RegistryIndex)
87 .collect::<Vec<RegistryIndex>>();
88
89 let log_bundle = config.core.log_inclusion_proofs(log_length, &leafs).await?;
90 let map_bundle = config.core.map_inclusion_proofs(log_length, &leafs).await?;
91
92 Ok(Json(InclusionResponse {
93 log: log_bundle.encode(),
94 map: map_bundle.encode(),
95 }))
96}