-
Notifications
You must be signed in to change notification settings - Fork 26
feat(rpc): add GET /lean/v0/genesis #455
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
base: main
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,69 @@ | ||
| use axum::{Router, extract::State, response::IntoResponse, routing::get}; | ||
| use ethlambda_storage::Store; | ||
| use serde::Serialize; | ||
|
|
||
| use crate::json_response; | ||
|
|
||
| #[derive(Serialize)] | ||
| struct GenesisResponse { | ||
| genesis_time: u64, | ||
| validator_count: u64, | ||
| } | ||
|
|
||
| async fn get_genesis(State(store): State<Store>) -> impl IntoResponse { | ||
| let genesis_time = store.config().genesis_time; | ||
| // Lean validators are fixed at genesis (no churn), so the current head | ||
| // state's validator registry always equals the genesis validator count. | ||
| let validator_count = store.head_state().validators.len() as u64; | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Prompt To Fix With AIThis is a comment left during a code review.
Path: crates/net/rpc/src/genesis.rs
Line: 15
Comment:
**Full state clone on every request to read one field**
`store.head_state()` deserializes and clones the entire `State` object just to call `.validators.len()`. Since genesis data is immutable by definition, this full-state clone on every GET is wasteful. Consider caching the genesis validator count at startup, or reading only the relevant field rather than materializing the whole state.
How can I resolve this? If you propose a fix, please make it concise.Note: If this suggestion doesn't match your team's coding style, reply to this and let me know. I'll remember it for next time! |
||
| json_response(GenesisResponse { | ||
| genesis_time, | ||
| validator_count, | ||
| }) | ||
| } | ||
|
|
||
| pub(crate) fn routes() -> Router<Store> { | ||
| Router::new().route("/lean/v0/genesis", get(get_genesis)) | ||
| } | ||
|
|
||
| #[cfg(test)] | ||
| mod tests { | ||
| use super::*; | ||
| use axum::{ | ||
| body::Body, | ||
| http::{Request, StatusCode}, | ||
| }; | ||
| use ethlambda_storage::{Store, backend::InMemoryBackend}; | ||
| use ethlambda_types::state::{State, Validator}; | ||
| use http_body_util::BodyExt; | ||
| use std::sync::Arc; | ||
| use tower::ServiceExt; | ||
|
|
||
| #[tokio::test] | ||
| async fn genesis_returns_time_and_validator_count() { | ||
| // Build a state with 3 validators so the assertion is non-vacuous. | ||
| let dummy_validator = |index: u64| Validator { | ||
| attestation_pubkey: [0u8; 52], | ||
| proposal_pubkey: [0u8; 52], | ||
| index, | ||
| }; | ||
| let validators = vec![dummy_validator(0), dummy_validator(1), dummy_validator(2)]; | ||
| let state = State::from_genesis(1000, validators); | ||
|
|
||
| let store = Store::from_anchor_state(Arc::new(InMemoryBackend::new()), state); | ||
| let app = routes().with_state(store); | ||
| let resp = app | ||
| .oneshot( | ||
| Request::builder() | ||
| .uri("/lean/v0/genesis") | ||
| .body(Body::empty()) | ||
| .unwrap(), | ||
| ) | ||
| .await | ||
| .unwrap(); | ||
| assert_eq!(resp.status(), StatusCode::OK); | ||
| let body = resp.into_body().collect().await.unwrap().to_bytes(); | ||
| let json: serde_json::Value = serde_json::from_slice(&body).unwrap(); | ||
| assert_eq!(json["genesis_time"], 1000); | ||
| assert_eq!(json["validator_count"], 3); | ||
| } | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
store.head_state()returns the current, evolving head state, not the genesis state. The PR description says this endpoint returns the "genesis validator set," but as the chain progresses and validators are added or removed,head_state().validators.len()will diverge from the genesis validator count. A client relying on this to "verify they are on the correct network" could observe different counts depending on when they query, making the field unreliable for its stated purpose. The genesis validator set should be read from the anchor/genesis state, not from the live head.Prompt To Fix With AI