diff --git a/crates/net/rpc/Cargo.toml b/crates/net/rpc/Cargo.toml index c1b8e1f..b6705ac 100644 --- a/crates/net/rpc/Cargo.toml +++ b/crates/net/rpc/Cargo.toml @@ -15,6 +15,7 @@ tokio.workspace = true ethlambda-metrics.workspace = true tracing.workspace = true ethlambda-storage.workspace = true +ethlambda-types.workspace = true serde.workspace = true serde_json.workspace = true diff --git a/crates/net/rpc/src/lib.rs b/crates/net/rpc/src/lib.rs index 9c42a70..d577a70 100644 --- a/crates/net/rpc/src/lib.rs +++ b/crates/net/rpc/src/lib.rs @@ -1,7 +1,11 @@ use std::net::SocketAddr; -use axum::{Json, Router, response::IntoResponse, routing::get}; +use axum::{Json, Router, http::HeaderValue, http::header, response::IntoResponse, routing::get}; use ethlambda_storage::Store; +use ethlambda_types::primitives::Encode; + +pub(crate) const JSON_CONTENT_TYPE: &str = "application/json; charset=utf-8"; +pub(crate) const SSZ_CONTENT_TYPE: &str = "application/octet-stream"; pub mod metrics; @@ -35,14 +39,32 @@ async fn get_latest_finalized_state( let state = store .get_state(&finalized.root) .expect("finalized state exists"); - Json(state) + ssz_response(state.as_ssz_bytes()) } async fn get_latest_justified_state( axum::extract::State(store): axum::extract::State, ) -> impl IntoResponse { let checkpoint = store.latest_justified(); - Json(checkpoint) + json_response(checkpoint) +} + +fn json_response(value: T) -> axum::response::Response { + let mut response = Json(value).into_response(); + response.headers_mut().insert( + header::CONTENT_TYPE, + HeaderValue::from_static(JSON_CONTENT_TYPE), + ); + response +} + +fn ssz_response(bytes: Vec) -> axum::response::Response { + let mut response = bytes.into_response(); + response.headers_mut().insert( + header::CONTENT_TYPE, + HeaderValue::from_static(SSZ_CONTENT_TYPE), + ); + response } #[cfg(test)] @@ -126,12 +148,15 @@ mod tests { #[tokio::test] async fn test_get_latest_finalized_state() { + use ethlambda_types::primitives::Encode; + let state = create_test_state(); let store = Store::from_genesis(state); - // Get the expected state from the store to build expected JSON + // Get the expected state from the store let finalized = store.latest_finalized(); let expected_state = store.get_state(&finalized.root).unwrap(); + let expected_ssz = expected_state.as_ssz_bytes(); let app = build_api_router(store); @@ -146,39 +171,12 @@ mod tests { .unwrap(); assert_eq!(response.status(), StatusCode::OK); - - let body = response.into_body().collect().await.unwrap().to_bytes(); - let returned_state: serde_json::Value = serde_json::from_slice(&body).unwrap(); - - let header = &expected_state.latest_block_header; assert_eq!( - returned_state, - json!({ - "config": { - "genesis_time": expected_state.config.genesis_time - }, - "slot": expected_state.slot, - "latest_block_header": { - "slot": header.slot, - "proposer_index": header.proposer_index, - "parent_root": format!("{:#x}", header.parent_root), - "state_root": format!("{:#x}", header.state_root), - "body_root": format!("{:#x}", header.body_root) - }, - "latest_justified": { - "slot": expected_state.latest_justified.slot, - "root": format!("{:#x}", expected_state.latest_justified.root) - }, - "latest_finalized": { - "slot": expected_state.latest_finalized.slot, - "root": format!("{:#x}", expected_state.latest_finalized.root) - }, - "historical_block_hashes": [], - "justified_slots": "0x01", - "validators": [], - "justifications_roots": [], - "justifications_validators": "0x01" - }) + response.headers().get(header::CONTENT_TYPE).unwrap(), + SSZ_CONTENT_TYPE ); + + let body = response.into_body().collect().await.unwrap().to_bytes(); + assert_eq!(body.as_ref(), expected_ssz.as_slice()); } } diff --git a/crates/net/rpc/src/metrics.rs b/crates/net/rpc/src/metrics.rs index c3edac6..aadb021 100644 --- a/crates/net/rpc/src/metrics.rs +++ b/crates/net/rpc/src/metrics.rs @@ -1,4 +1,4 @@ -use axum::{Router, http::HeaderValue, response::IntoResponse, routing::get}; +use axum::{Router, http::HeaderValue, http::header, response::IntoResponse, routing::get}; use ethlambda_metrics::gather_default_metrics; use tracing::warn; @@ -9,7 +9,12 @@ pub fn start_prometheus_metrics_api() -> Router { } pub(crate) async fn get_health() -> impl IntoResponse { - r#"{"status": "healthy", "service": "lean-spec-api"}"# + let mut response = r#"{"status":"healthy","service":"lean-spec-api"}"#.into_response(); + response.headers_mut().insert( + header::CONTENT_TYPE, + HeaderValue::from_static(crate::JSON_CONTENT_TYPE), + ); + response } pub(crate) async fn get_metrics() -> impl IntoResponse { @@ -20,6 +25,8 @@ pub(crate) async fn get_metrics() -> impl IntoResponse { .unwrap_or_default() .into_response(); let content_type = HeaderValue::from_static("text/plain; version=0.0.4; charset=utf-8"); - response.headers_mut().insert("content-type", content_type); + response + .headers_mut() + .insert(header::CONTENT_TYPE, content_type); response }