Ensure light_client/updates endpoint returns spec compliant SSZ data (#7230)

Closes #7167


  - Ensure the fork digest is generated from ther light client updates attested header and not the signature slot
- Ensure the format of the SSZ response is spec compliant
This commit is contained in:
Eitan Seri-Levi
2025-04-10 21:47:27 -07:00
committed by GitHub
parent 9304a592bf
commit ef8ec35ac5
2 changed files with 17 additions and 15 deletions

View File

@@ -4,7 +4,7 @@ use crate::version::{
use beacon_chain::{BeaconChain, BeaconChainError, BeaconChainTypes}; use beacon_chain::{BeaconChain, BeaconChainError, BeaconChainTypes};
use eth2::types::{ use eth2::types::{
self as api_types, ChainSpec, ForkVersionedResponse, LightClientUpdate, self as api_types, ChainSpec, ForkVersionedResponse, LightClientUpdate,
LightClientUpdateResponseChunk, LightClientUpdateSszResponse, LightClientUpdatesQuery, LightClientUpdateResponseChunk, LightClientUpdateResponseChunkInner, LightClientUpdatesQuery,
}; };
use ssz::Encode; use ssz::Encode;
use std::sync::Arc; use std::sync::Arc;
@@ -37,15 +37,9 @@ pub fn get_light_client_updates<T: BeaconChainTypes>(
.map(|update| map_light_client_update_to_ssz_chunk::<T>(&chain, update)) .map(|update| map_light_client_update_to_ssz_chunk::<T>(&chain, update))
.collect::<Vec<LightClientUpdateResponseChunk>>(); .collect::<Vec<LightClientUpdateResponseChunk>>();
let ssz_response = LightClientUpdateSszResponse {
response_chunk_len: (light_client_updates.len() as u64).to_le_bytes().to_vec(),
response_chunk: response_chunks.as_ssz_bytes(),
}
.as_ssz_bytes();
Response::builder() Response::builder()
.status(200) .status(200)
.body(ssz_response) .body(response_chunks.as_ssz_bytes())
.map(|res: Response<Vec<u8>>| add_ssz_content_type_header(res)) .map(|res: Response<Vec<u8>>| add_ssz_content_type_header(res))
.map_err(|e| { .map_err(|e| {
warp_utils::reject::custom_server_error(format!( warp_utils::reject::custom_server_error(format!(
@@ -159,16 +153,24 @@ fn map_light_client_update_to_ssz_chunk<T: BeaconChainTypes>(
) -> LightClientUpdateResponseChunk { ) -> LightClientUpdateResponseChunk {
let fork_name = chain let fork_name = chain
.spec .spec
.fork_name_at_slot::<T::EthSpec>(*light_client_update.signature_slot()); .fork_name_at_slot::<T::EthSpec>(light_client_update.attested_header_slot());
let fork_digest = ChainSpec::compute_fork_digest( let fork_digest = ChainSpec::compute_fork_digest(
chain.spec.fork_version_for_name(fork_name), chain.spec.fork_version_for_name(fork_name),
chain.genesis_validators_root, chain.genesis_validators_root,
); );
LightClientUpdateResponseChunk { let payload = light_client_update.as_ssz_bytes();
let response_chunk_len = fork_digest.len() + payload.len();
let response_chunk = LightClientUpdateResponseChunkInner {
context: fork_digest, context: fork_digest,
payload: light_client_update.as_ssz_bytes(), payload,
};
LightClientUpdateResponseChunk {
response_chunk_len: response_chunk_len as u64,
response_chunk,
} }
} }

View File

@@ -802,13 +802,13 @@ pub struct LightClientUpdatesQuery {
} }
#[derive(Encode, Decode)] #[derive(Encode, Decode)]
pub struct LightClientUpdateSszResponse { pub struct LightClientUpdateResponseChunk {
pub response_chunk_len: Vec<u8>, pub response_chunk_len: u64,
pub response_chunk: Vec<u8>, pub response_chunk: LightClientUpdateResponseChunkInner,
} }
#[derive(Encode, Decode)] #[derive(Encode, Decode)]
pub struct LightClientUpdateResponseChunk { pub struct LightClientUpdateResponseChunkInner {
pub context: [u8; 4], pub context: [u8; 4],
pub payload: Vec<u8>, pub payload: Vec<u8>,
} }