Skip to content

Commit

Permalink
gateway
Browse files Browse the repository at this point in the history
  • Loading branch information
jbcaron committed Sep 9, 2024
1 parent 3ed74b0 commit ba05390
Show file tree
Hide file tree
Showing 17 changed files with 232 additions and 178 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

## Next release

- feat: new crate gateway client & server
- refactor: class import from FGW
- code docs: documented how get_storage_at is implemented
- fix: L1 rpc <=> network mismatch
Expand Down
5 changes: 4 additions & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions crates/client/gateway/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ targets = ["x86_64-unknown-linux-gnu"]
[dependencies]

# Deoxys
mc-db = { workspace = true }
mp-block = { workspace = true }
mp-gateway = { workspace = true }
mp-state-update = { workspace = true }
Expand All @@ -30,6 +31,7 @@ hyper = { workspace = true }
log = { workspace = true }
reqwest = { workspace = true }
serde = { workspace = true, features = ["derive"] }
serde_json = { workspace = true }
thiserror = { workspace = true }
tokio = { workspace = true }
url = { workspace = true }
Expand Down
6 changes: 6 additions & 0 deletions crates/client/gateway/src/error.rs
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,12 @@ pub struct StarknetError {
pub message: String,
}

impl StarknetError {
pub fn new(code: StarknetErrorCode, message: String) -> Self {
Self { code, message }
}
}

impl std::error::Error for StarknetError {}

impl std::fmt::Display for StarknetError {
Expand Down
2 changes: 1 addition & 1 deletion crates/client/gateway/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
pub mod client;
pub mod error;
// pub mod server;
pub mod server;
60 changes: 17 additions & 43 deletions crates/client/gateway/src/server/handler.rs
Original file line number Diff line number Diff line change
@@ -1,47 +1,21 @@
async fn router(req: Request<Body>) -> Result<Response<Body>, Infallible> {
match (req.method(), req.uri().path()) {
(&Method::GET, "/") => handle_root(req).await,
// Endpoint "/hello"
(&Method::GET, "/hello") => handle_hello(req).await,
// Endpoint inconnu
_ => {
let mut not_found = Response::new(Body::from("Not Found"));
*not_found.status_mut() = StatusCode::NOT_FOUND;
Ok(not_found)
}
}
}
use std::sync::Arc;

use hyper::{Body, Request, Response};
use mc_db::MadaraBackend;

use super::helpers::{block_id_from_params, get_params_from_request};

pub async fn handle_get_block(req: Request<Body>, _backend: Arc<MadaraBackend>) -> Response<Body> {
let params = get_params_from_request(&req);
let _block_id = match block_id_from_params(&params) {
Ok(block_id) => block_id,
// Return the error response if the request is malformed
Err(e) => return e.into(),
};

async fn router(req: Request<Body>, config: Arc<Config>) -> Result<Response<Body>, Infallible> {
match (req.method(), req.uri().path()) {
// Routes pour "/feeder_gateway/requetes"
(&Method::GET, "/feeder_gateway/requetes") if config.enable_feeder_gateway => {
handle_get_feeder_gateway(req).await
}
(&Method::POST, "/feeder_gateway/requetes") if config.enable_feeder_gateway => {
handle_other_feeder_gateway(req).await
}
// Routes pour "/feeder/requetes"
(&Method::POST, "/feeder/requetes") if config.enable_feeder => handle_post_feeder(req).await,
// Gestion des cas non trouvés ou non autorisés
_ => {
if !config.enable_feeder_gateway && req.uri().path().starts_with("/feeder_gateway") {
let mut not_allowed = Response::new(Body::from("Feeder Gateway Service désactivé"));
*not_allowed.status_mut() = StatusCode::SERVICE_UNAVAILABLE;
Ok(not_allowed)
} else if !config.enable_feeder && req.uri().path().starts_with("/feeder") {
let mut not_allowed = Response::new(Body::from("Feeder Service désactivé"));
*not_allowed.status_mut() = StatusCode::SERVICE_UNAVAILABLE;
Ok(not_allowed)
} else {
let mut not_found = Response::new(Body::from("Not Found"));
*not_found.status_mut() = StatusCode::NOT_FOUND;
Ok(not_found)
}
}
}
Response::new(Body::from("Not Implemented"))
}

async fn handle_root(_req: Request<Body>) -> Result<Response<Body>, Infallible> {
Ok(Response::new(Body::from("Bienvenue à la racine!")))
pub async fn handle_get_state_update(_req: Request<Body>, _backend: Arc<MadaraBackend>) -> Response<Body> {
Response::new(Body::from("Not Implemented"))
}
98 changes: 94 additions & 4 deletions crates/client/gateway/src/server/helpers.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,102 @@
// Helper function to generate a service unavailable response
use std::collections::HashMap;

use hyper::{header, Body, Request, Response, StatusCode};
use mp_block::{BlockId, BlockTag};
use serde::Serialize;
use starknet_types_core::felt::Felt;
use url::Url;

use crate::error::{StarknetError, StarknetErrorCode};

pub(crate) fn service_unavailable_response(service_name: &str) -> Response<Body> {
Response::builder()
.status(StatusCode::SERVICE_UNAVAILABLE)
.body(Body::from(format!("{} Service disabled", service_name)))
.unwrap()
.expect("Failed to build SERVICE_UNAVAILABLE response with a valid status and body")
}

// Helper function to generate a not found response
pub(crate) fn not_found_response() -> Response<Body> {
Response::builder().status(StatusCode::NOT_FOUND).body(Body::from("Not Found")).unwrap()
Response::builder()
.status(StatusCode::NOT_FOUND)
.body(Body::from("Not Found"))
.expect("Failed to build NOT_FOUND response with a valid status and body")
}

pub(crate) fn internal_error_response() -> Response<Body> {
Response::builder()
.status(StatusCode::INTERNAL_SERVER_ERROR)
.body(Body::from("Internal Server Error"))
.expect("Failed to build INTERNAL_SERVER_ERROR response with a valid status and body")
}

pub(crate) fn not_implemented_response() -> Response<Body> {
Response::builder()
.status(StatusCode::NOT_IMPLEMENTED)
.body(Body::from("Not Implemented"))
.expect("Failed to build NOT_IMPLEMENTED response with a valid status and body")
}

/// Creates a JSON response with the given status code and a body that can be serialized to JSON.
///
/// If the serialization fails, this function returns a 500 Internal Server Error response.
pub(crate) fn create_json_response<T>(status: StatusCode, body: &T) -> Response<Body>
where
T: Serialize,
{
// Serialize the body to JSON
let body = match serde_json::to_string(body) {
Ok(body) => body,
Err(e) => {
log::error!("Failed to serialize response body: {}", e);
return internal_error_response();
}
};
// Build the response with the specified status code and serialized body
match Response::builder().status(status).header(header::CONTENT_TYPE, "application/json").body(Body::from(body)) {
Ok(response) => response,
Err(e) => {
log::error!("Failed to build response: {}", e);
internal_error_response()
}
}
}

pub(crate) fn get_params_from_request(req: &Request<Body>) -> HashMap<String, String> {
let uri = req.uri();
let req_url =
Url::parse(&uri.to_string()).expect("Failed to parse URI from request: URI should be a valid URL format");
let params = req_url.query_pairs();
let mut query_params = HashMap::new();
for (key, value) in params {
query_params.insert(key.to_string(), value.to_string());
}
query_params
}

// blockNumber or blockHash
pub(crate) fn block_id_from_params(params: &HashMap<String, String>) -> Result<BlockId, StarknetError> {
if let Some(block_number) = params.get("block_number") {
match block_number.as_str() {
"latest" => Ok(BlockId::Tag(BlockTag::Latest)),
"pending" => Ok(BlockId::Tag(BlockTag::Pending)),
_ => {
let block_number = block_number.parse().map_err(|e: std::num::ParseIntError| {
StarknetError::new(StarknetErrorCode::MalformedRequest, e.to_string())
})?;
Ok(BlockId::Number(block_number))
}
}
} else if let Some(block_hash) = params.get("block_hash") {
let block_hash = Felt::from_hex(block_hash)
.map_err(|e| StarknetError::new(StarknetErrorCode::MalformedRequest, e.to_string()))?;
Ok(BlockId::Hash(block_hash))
} else {
Err(StarknetError::new(StarknetErrorCode::MalformedRequest, "block_number or block_hash not found".to_string()))
}
}

impl From<StarknetError> for hyper::Response<hyper::Body> {
fn from(error: StarknetError) -> Self {
create_json_response(hyper::StatusCode::BAD_REQUEST, &error)
}
}
2 changes: 1 addition & 1 deletion crates/client/gateway/src/server/mod.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
mod handler;
mod helpers;
mod router;
pub mod service;
pub mod worker;
46 changes: 23 additions & 23 deletions crates/client/gateway/src/server/router.rs
Original file line number Diff line number Diff line change
@@ -1,41 +1,41 @@
use std::{convert::Infallible, sync::Arc};

use hyper::{Body, Method, Request, Response, StatusCode};
use hyper::{Body, Method, Request, Response};
use mc_db::MadaraBackend;

use super::{helpers::{not_found_response, service_unavailable_response}};
use super::handler::{handle_get_block, handle_get_state_update};
use super::helpers::{not_found_response, not_implemented_response, service_unavailable_response};

// Main router to redirect to the appropriate sub-router
pub(crate) async fn main_router(req: Request<Body>, config: Arc<MadaraBackend>, gateway_enable: bool, gateway_external: bool) -> Result<Response<Body>, Infallible> {
match (req.uri().path(), config.feeder_gateway, config.gateway) {
(path, true, _) if path.starts_with("/feeder_gateway") => feeder_gateway_router(req).await,
(path, _, true) if path.starts_with("/feeder") => feeder_router(req).await,
(path, false, _) if path.starts_with("/feeder_gateway") => Ok(service_unavailable_response("Feeder Gateway")),
(path, _, false) if path.starts_with("/feeder") => Ok(service_unavailable_response("Feeder")),
pub(crate) async fn main_router(
req: Request<Body>,
backend: Arc<MadaraBackend>,
feeder_gateway_enable: bool,
gateway_enable: bool,
) -> Result<Response<Body>, Infallible> {
match (req.uri().path(), feeder_gateway_enable, gateway_enable) {
("/health", _, _) => Ok(Response::new(Body::from("OK"))),
(path, true, _) if path.starts_with("/feeder_gateway/") => feeder_gateway_router(req, backend).await,
(path, _, true) if path.starts_with("/feeder/") => gateway_router(req, backend).await,
(path, false, _) if path.starts_with("/feeder_gateway/") => Ok(service_unavailable_response("Feeder Gateway")),
(path, _, false) if path.starts_with("/feeder/") => Ok(service_unavailable_response("Feeder")),
_ => Ok(not_found_response()),
}
}

// Router for requests related to feeder_gateway
async fn feeder_gateway_router(req: Request<Body>) -> Result<Response<Body>, Infallible> {
async fn feeder_gateway_router(req: Request<Body>, backend: Arc<MadaraBackend>) -> Result<Response<Body>, Infallible> {
match (req.method(), req.uri().path()) {
(&Method::GET, "/feeder_gateway/get_block") => handle_get_block(req).await,
(&Method::POST, "/feeder_gateway/get_state_update") => handle_get_state_update(req).await,
_ => {
let mut not_found = Response::new(Body::from("Not Found"));
*not_found.status_mut() = StatusCode::NOT_FOUND;
Ok(not_found)
}
(&Method::GET, "/feeder_gateway/get_block") => Ok(handle_get_block(req, backend).await),
(&Method::POST, "/feeder_gateway/get_state_update") => Ok(handle_get_state_update(req, backend).await),
_ => Ok(not_found_response()),
}
}

// Router for requests related to feeder
async fn feeder_router(req: Request<Body>) -> Result<Response<Body>, Infallible> {
async fn gateway_router(req: Request<Body>, _backend: Arc<MadaraBackend>) -> Result<Response<Body>, Infallible> {
match (req.method(), req.uri().path()) {
(&Method::POST, "/feeder/add_transaction") => handle_add_transaction(req).await,
_ => {
let mut not_found = Response::new(Body::from("Not Found"));
*not_found.status_mut() = StatusCode::NOT_FOUND;
Ok(not_found)
}
(&Method::POST, "/feeder/add_transaction") => Ok(not_implemented_response()),
_ => Ok(not_found_response()),
}
}
62 changes: 0 additions & 62 deletions crates/client/gateway/src/server/service.rs

This file was deleted.

Loading

0 comments on commit ba05390

Please sign in to comment.