Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Merged
merged 11 commits into from
Nov 28, 2023
35 changes: 35 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,35 @@
//! 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.
pub(crate) async fn endpoint(_fragments_batch: FragmentsBatch) -> AllResponses {
T200(OK(Json(FragmentsProcessingSummary::default())))
}
38 changes: 38 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,38 @@
//! 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},
},
};

#[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.
pub(crate) async fn endpoint(_fragment_ids: FragmentIds) -> AllResponses {
T200(OK(Json(HashMap::new())))
}
44 changes: 42 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,39 @@ 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"
)]
async fn fragments_post(
FelipeRosa marked this conversation as resolved.
Show resolved Hide resolved
&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"
)]
FelipeRosa marked this conversation as resolved.
Show resolved Hide resolved
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
}
}
28 changes: 28 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,28 @@
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),
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
use poem_openapi::{types::Example, Object, Union};

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

#[derive(Object)]
#[oai(example = false)]
stevenj marked this conversation as resolved.
Show resolved Hide resolved
/// Fragment is pending.
pub(crate) struct StatusPending;

#[derive(Object)]
#[oai(example = true)]
/// 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)]
/// Fragment is included in a block.
pub(crate) struct StatusInABlock {
pub date: BlockDate,
pub block: Hash,
}

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

#[derive(Union)]
#[oai(one_of = true)]
/// Possible fragment statuses.
pub(crate) enum FragmentStatus {
Pending(StatusPending),
Rejected(StatusRejected),
InABlock(StatusInABlock),
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
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![],
}
}
}
18 changes: 18 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,18 @@
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,
FelipeRosa marked this conversation as resolved.
Show resolved Hide resolved
}

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