Skip to content

Commit

Permalink
feat(fragments-endpoints): Add /fragments and /fragments/statuses com…
Browse files Browse the repository at this point in the history
…patibility endpoints (#93)

* feat(fragments-endpoints): Add /fragments and /fragments/statuses compatibility endpoints

* Fix fragment status object format and implement PR suggestions
  • Loading branch information
Felipe Rosa authored Nov 28, 2023
1 parent 54bd4ec commit 712dbf4
Show file tree
Hide file tree
Showing 9 changed files with 261 additions and 2 deletions.
36 changes: 36 additions & 0 deletions catalyst-gateway/bin/src/service/api/v1/fragments_post.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
//! Implementation of the GET /fragments endpoint
use poem_extensions::{response, UniResponse::T200};
use poem_openapi::payload::Json;

use crate::service::common::{
objects::{
fragments_batch::FragmentsBatch, fragments_processing_summary::FragmentsProcessingSummary,
},
responses::{
resp_2xx::OK,
resp_5xx::{ServerError, ServiceUnavailable},
},
};

/// All responses
pub(crate) type AllResponses = response! {
200: OK<Json<FragmentsProcessingSummary>>,
500: ServerError,
503: ServiceUnavailable,
};

/// # GET /fragments
///
/// Process a fragments batch.
///
/// ## Responses
///
/// * 200 No Content - Service is OK and can keep running.
/// * 500 Server Error - If anything within this function fails unexpectedly. (Possible
/// but unlikely)
/// * 503 Service Unavailable - Service is possibly not running reliably.
#[allow(clippy::unused_async)]
pub(crate) async fn endpoint(_fragments_batch: FragmentsBatch) -> AllResponses {
T200(OK(Json(FragmentsProcessingSummary::default())))
}
40 changes: 40 additions & 0 deletions catalyst-gateway/bin/src/service/api/v1/fragments_statuses.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
//! Implementation of the GET /fragments/statuses endpoint
use std::collections::HashMap;

use poem_extensions::{response, UniResponse::T200};
use poem_openapi::payload::Json;

use crate::service::common::{
objects::fragment_status::FragmentStatus,
responses::{
resp_2xx::OK,
resp_5xx::{ServerError, ServiceUnavailable},
},
};

/// Comma-separated (no spaces in between) list of fragment IDs.
#[derive(poem_openapi::NewType)]
pub(crate) struct FragmentIds(String);

/// All responses
pub(crate) type AllResponses = response! {
200: OK<Json<HashMap<String, FragmentStatus>>>,
500: ServerError,
503: ServiceUnavailable,
};

/// # GET /fragments/statuses
///
/// Get fragments statuses endpoint.
///
/// ## Responses
///
/// * 200 Fragments Statuses - Statuses of the fragments by id.
/// * 500 Server Error - If anything within this function fails unexpectedly. (Possible
/// but unlikely)
/// * 503 Service Unavailable - Service is possibly not running reliably.
#[allow(clippy::unused_async)]
pub(crate) async fn endpoint(_fragment_ids: FragmentIds) -> AllResponses {
T200(OK(Json(HashMap::new())))
}
46 changes: 44 additions & 2 deletions catalyst-gateway/bin/src/service/api/v1/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,14 +3,19 @@
use std::sync::Arc;

use poem::web::{Data, Path};
use poem_openapi::OpenApi;
use poem_openapi::{param::Query, payload::Json, OpenApi};

use crate::{
service::common::{objects::account_votes::AccountId, tags::ApiTags},
service::common::{
objects::{account_votes::AccountId, fragments_batch::FragmentsBatch},
tags::ApiTags,
},
state::State,
};

mod account_votes_get;
mod fragments_post;
mod fragments_statuses;

/// V1 API Endpoints
pub(crate) struct V1Api;
Expand All @@ -29,4 +34,41 @@ impl V1Api {
) -> account_votes_get::AllResponses {
account_votes_get::endpoint(state, account_id).await
}

/// Process fragments
///
/// Posts a fragments batch to be processed.
#[oai(
path = "/fragments",
method = "post",
operation_id = "fragments",
tag = "ApiTags::Fragments",
deprecated = true
)]
async fn fragments_post(
&self,
/// Batch of fragments to be processed.
Json(fragments_batch): Json<FragmentsBatch>,
) -> fragments_post::AllResponses {
fragments_post::endpoint(fragments_batch).await
}

/// Get Fragment Statuses
///
/// Get statuses of the fragments with the given ids.
#[oai(
path = "/fragments/statuses",
method = "get",
operation_id = "fragmentsStatuses",
tag = "ApiTags::Fragments",
deprecated = true
)]
async fn fragments_statuses(
&self,
/// Comma-separated list of fragment ids for which the statuses will
/// be retrieved.
Query(fragment_ids): Query<fragments_statuses::FragmentIds>,
) -> fragments_statuses::AllResponses {
fragments_statuses::endpoint(fragment_ids).await
}
}
30 changes: 30 additions & 0 deletions catalyst-gateway/bin/src/service/common/objects/block.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
//! Defines API schemas of block related types.
use poem_openapi::{types::Example, NewType, Object};

#[derive(NewType)]
/// Epoch number.
pub(crate) struct Epoch(pub u32);

#[derive(NewType)]
/// Slot number.
pub(crate) struct Slot(pub u32);

#[derive(Object)]
#[oai(example = true)]
/// Block time defined as the pair (epoch, slot).
pub(crate) struct BlockDate {
/// Block's epoch.
pub epoch: Epoch,
/// Block's slot number.
pub slot_id: Slot,
}

impl Example for BlockDate {
fn example() -> Self {
Self {
epoch: Epoch(1),
slot_id: Slot(5),
}
}
}
57 changes: 57 additions & 0 deletions catalyst-gateway/bin/src/service/common/objects/fragment_status.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
//! Defines API schemas of fragment status types.
use poem_openapi::{types::Example, Object, Union};

use crate::service::common::objects::{block::BlockDate, hash::Hash};

#[derive(Object)]
#[oai(example = false)]
/// DEPRECATED: Fragment is pending.
pub(crate) struct StatusPending;

#[derive(Object)]
#[oai(example = true)]
/// DEPRECATED: Fragment was rejected.
pub(crate) struct StatusRejected {
/// Reason the fragment was rejected.
pub reason: String,
}

impl Example for StatusRejected {
fn example() -> Self {
Self {
reason: "Transaction malformed".to_string(),
}
}
}

#[derive(Object)]
#[oai(example = true)]
/// DEPRECATED: Fragment is included in a block.
pub(crate) struct StatusInABlock {
/// Block date at which the fragment was included in a block.
pub date: BlockDate,
/// Hash of the block the fragment was included in.
pub block: Hash,
}

impl Example for StatusInABlock {
fn example() -> Self {
Self {
date: BlockDate::example(),
block: Hash::example(),
}
}
}

#[derive(Union)]
#[oai(one_of = true)]
/// DEPRECATED: Possible fragment statuses.
pub(crate) enum FragmentStatus {
/// Fragment is pending inclusion in a block.
Pending(StatusPending),
/// Fragment was rejected.
Rejected(StatusRejected),
/// Fragment was included in a block.
InABlock(StatusInABlock),
}
28 changes: 28 additions & 0 deletions catalyst-gateway/bin/src/service/common/objects/fragments_batch.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
//! Defines API schemas for fragment batch types.
use poem_openapi::{types::Example, NewType, Object};
use serde::Deserialize;

#[derive(NewType, Deserialize)]
/// Hex-encoded fragment's bytes.
pub(crate) struct FragmentDef(String);

#[derive(Object, Deserialize)]
#[oai(example = true)]
/// Batch of hex-encoded fragments.
pub(crate) struct FragmentsBatch {
/// Fragments are processed sequentially. If this is true, processing is
/// stopped after the first error occurs.
pub fail_fast: bool,
/// Array of hex-encoded fragments bytes.
pub fragments: Vec<FragmentDef>,
}

impl Example for FragmentsBatch {
fn example() -> Self {
Self {
fail_fast: false,
fragments: vec![],
}
}
}
20 changes: 20 additions & 0 deletions catalyst-gateway/bin/src/service/common/objects/hash.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
//! Defines API schemas for hash types.
use poem_openapi::{types::Example, Object};

#[derive(Object)]
#[oai(example = true)]
/// Blake2b256 hash wrapper.
pub(crate) struct Hash {
/// Blake2b256 hash encoded in hex.
#[oai(validator(max_length = 64, min_length = 64, pattern = "[0-9a-f]{64}"))]
pub hash: String,
}

impl Example for Hash {
fn example() -> Self {
Self {
hash: "928b20366943e2afd11ebc0eae2e53a93bf177a4fcf35bcc64d503704e65e202".to_string(),
}
}
}
4 changes: 4 additions & 0 deletions catalyst-gateway/bin/src/service/common/objects/mod.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
//! This module contains common and re-usable objects.
pub(crate) mod account_votes;
pub(crate) mod block;
pub(crate) mod delegate_public_key;
pub(crate) mod event_id;
pub(crate) mod fragment_status;
pub(crate) mod fragments_batch;
pub(crate) mod fragments_processing_summary;
pub(crate) mod hash;
pub(crate) mod stake_public_key;
pub(crate) mod vote_plan;
pub(crate) mod voter_group_id;
Expand Down
2 changes: 2 additions & 0 deletions catalyst-gateway/bin/src/service/common/tags.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@ use poem_openapi::Tags;
/// `OpenAPI` Tags
#[derive(Tags)]
pub(crate) enum ApiTags {
/// Fragment endpoints
Fragments,
/// Health Endpoints
Health,
/// Information relating to Voter Registration, Delegations and Calculated Voting
Expand Down

0 comments on commit 712dbf4

Please sign in to comment.