Skip to content

Commit 740507e

Browse files
authored
fix: change finalized state route to return SSZ instead of JSON (#59)
* fix: use correct content-type header value * fix: return finalized state as SSZ
1 parent 2e2a431 commit 740507e

File tree

3 files changed

+45
-39
lines changed

3 files changed

+45
-39
lines changed

crates/net/rpc/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ tokio.workspace = true
1515
ethlambda-metrics.workspace = true
1616
tracing.workspace = true
1717
ethlambda-storage.workspace = true
18+
ethlambda-types.workspace = true
1819
serde.workspace = true
1920
serde_json.workspace = true
2021

crates/net/rpc/src/lib.rs

Lines changed: 34 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,11 @@
11
use std::net::SocketAddr;
22

3-
use axum::{Json, Router, response::IntoResponse, routing::get};
3+
use axum::{Json, Router, http::HeaderValue, http::header, response::IntoResponse, routing::get};
44
use ethlambda_storage::Store;
5+
use ethlambda_types::primitives::Encode;
6+
7+
pub(crate) const JSON_CONTENT_TYPE: &str = "application/json; charset=utf-8";
8+
pub(crate) const SSZ_CONTENT_TYPE: &str = "application/octet-stream";
59

610
pub mod metrics;
711

@@ -35,14 +39,32 @@ async fn get_latest_finalized_state(
3539
let state = store
3640
.get_state(&finalized.root)
3741
.expect("finalized state exists");
38-
Json(state)
42+
ssz_response(state.as_ssz_bytes())
3943
}
4044

4145
async fn get_latest_justified_state(
4246
axum::extract::State(store): axum::extract::State<Store>,
4347
) -> impl IntoResponse {
4448
let checkpoint = store.latest_justified();
45-
Json(checkpoint)
49+
json_response(checkpoint)
50+
}
51+
52+
fn json_response<T: serde::Serialize>(value: T) -> axum::response::Response {
53+
let mut response = Json(value).into_response();
54+
response.headers_mut().insert(
55+
header::CONTENT_TYPE,
56+
HeaderValue::from_static(JSON_CONTENT_TYPE),
57+
);
58+
response
59+
}
60+
61+
fn ssz_response(bytes: Vec<u8>) -> axum::response::Response {
62+
let mut response = bytes.into_response();
63+
response.headers_mut().insert(
64+
header::CONTENT_TYPE,
65+
HeaderValue::from_static(SSZ_CONTENT_TYPE),
66+
);
67+
response
4668
}
4769

4870
#[cfg(test)]
@@ -126,12 +148,15 @@ mod tests {
126148

127149
#[tokio::test]
128150
async fn test_get_latest_finalized_state() {
151+
use ethlambda_types::primitives::Encode;
152+
129153
let state = create_test_state();
130154
let store = Store::from_genesis(state);
131155

132-
// Get the expected state from the store to build expected JSON
156+
// Get the expected state from the store
133157
let finalized = store.latest_finalized();
134158
let expected_state = store.get_state(&finalized.root).unwrap();
159+
let expected_ssz = expected_state.as_ssz_bytes();
135160

136161
let app = build_api_router(store);
137162

@@ -146,39 +171,12 @@ mod tests {
146171
.unwrap();
147172

148173
assert_eq!(response.status(), StatusCode::OK);
149-
150-
let body = response.into_body().collect().await.unwrap().to_bytes();
151-
let returned_state: serde_json::Value = serde_json::from_slice(&body).unwrap();
152-
153-
let header = &expected_state.latest_block_header;
154174
assert_eq!(
155-
returned_state,
156-
json!({
157-
"config": {
158-
"genesis_time": expected_state.config.genesis_time
159-
},
160-
"slot": expected_state.slot,
161-
"latest_block_header": {
162-
"slot": header.slot,
163-
"proposer_index": header.proposer_index,
164-
"parent_root": format!("{:#x}", header.parent_root),
165-
"state_root": format!("{:#x}", header.state_root),
166-
"body_root": format!("{:#x}", header.body_root)
167-
},
168-
"latest_justified": {
169-
"slot": expected_state.latest_justified.slot,
170-
"root": format!("{:#x}", expected_state.latest_justified.root)
171-
},
172-
"latest_finalized": {
173-
"slot": expected_state.latest_finalized.slot,
174-
"root": format!("{:#x}", expected_state.latest_finalized.root)
175-
},
176-
"historical_block_hashes": [],
177-
"justified_slots": "0x01",
178-
"validators": [],
179-
"justifications_roots": [],
180-
"justifications_validators": "0x01"
181-
})
175+
response.headers().get(header::CONTENT_TYPE).unwrap(),
176+
SSZ_CONTENT_TYPE
182177
);
178+
179+
let body = response.into_body().collect().await.unwrap().to_bytes();
180+
assert_eq!(body.as_ref(), expected_ssz.as_slice());
183181
}
184182
}

crates/net/rpc/src/metrics.rs

Lines changed: 10 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
use axum::{Router, http::HeaderValue, response::IntoResponse, routing::get};
1+
use axum::{Router, http::HeaderValue, http::header, response::IntoResponse, routing::get};
22
use ethlambda_metrics::gather_default_metrics;
33
use tracing::warn;
44

@@ -9,7 +9,12 @@ pub fn start_prometheus_metrics_api() -> Router {
99
}
1010

1111
pub(crate) async fn get_health() -> impl IntoResponse {
12-
r#"{"status": "healthy", "service": "lean-spec-api"}"#
12+
let mut response = r#"{"status":"healthy","service":"lean-spec-api"}"#.into_response();
13+
response.headers_mut().insert(
14+
header::CONTENT_TYPE,
15+
HeaderValue::from_static(crate::JSON_CONTENT_TYPE),
16+
);
17+
response
1318
}
1419

1520
pub(crate) async fn get_metrics() -> impl IntoResponse {
@@ -20,6 +25,8 @@ pub(crate) async fn get_metrics() -> impl IntoResponse {
2025
.unwrap_or_default()
2126
.into_response();
2227
let content_type = HeaderValue::from_static("text/plain; version=0.0.4; charset=utf-8");
23-
response.headers_mut().insert("content-type", content_type);
28+
response
29+
.headers_mut()
30+
.insert(header::CONTENT_TYPE, content_type);
2431
response
2532
}

0 commit comments

Comments
 (0)