Skip to content

Commit 90fa7c2

Browse files
authored
Fix ssz formatting for /light_client/updates beacon API endpoint (#7806)
#7759 We were incorrectly encoding the full response from `/light_client/updates` instead of only encoding the light client update
1 parent 42f6d7b commit 90fa7c2

File tree

4 files changed

+80
-16
lines changed

4 files changed

+80
-16
lines changed

beacon_node/http_api/src/light_client.rs

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -34,13 +34,15 @@ pub fn get_light_client_updates<T: BeaconChainTypes>(
3434
match accept_header {
3535
Some(api_types::Accept::Ssz) => {
3636
let response_chunks = light_client_updates
37-
.iter()
38-
.map(|update| map_light_client_update_to_ssz_chunk::<T>(&chain, update))
39-
.collect::<Vec<LightClientUpdateResponseChunk>>();
37+
.into_iter()
38+
.flat_map(|update| {
39+
map_light_client_update_to_response_chunk::<T>(&chain, update).as_ssz_bytes()
40+
})
41+
.collect();
4042

4143
Response::builder()
4244
.status(200)
43-
.body(response_chunks.as_ssz_bytes())
45+
.body(response_chunks)
4446
.map(|res: Response<Vec<u8>>| add_ssz_content_type_header(res))
4547
.map_err(|e| {
4648
warp_utils::reject::custom_server_error(format!(
@@ -146,21 +148,20 @@ pub fn validate_light_client_updates_request<T: BeaconChainTypes>(
146148
Ok(())
147149
}
148150

149-
fn map_light_client_update_to_ssz_chunk<T: BeaconChainTypes>(
151+
fn map_light_client_update_to_response_chunk<T: BeaconChainTypes>(
150152
chain: &BeaconChain<T>,
151-
light_client_update: &LightClientUpdate<T::EthSpec>,
152-
) -> LightClientUpdateResponseChunk {
153+
light_client_update: LightClientUpdate<T::EthSpec>,
154+
) -> LightClientUpdateResponseChunk<T::EthSpec> {
153155
let epoch = light_client_update
154156
.attested_header_slot()
155157
.epoch(T::EthSpec::slots_per_epoch());
156158
let fork_digest = chain.compute_fork_digest(epoch);
157159

158-
let payload = light_client_update.as_ssz_bytes();
159-
let response_chunk_len = fork_digest.len() + payload.len();
160+
let response_chunk_len = fork_digest.len() + light_client_update.ssz_bytes_len();
160161

161162
let response_chunk = LightClientUpdateResponseChunkInner {
162163
context: fork_digest,
163-
payload,
164+
payload: light_client_update,
164165
};
165166

166167
LightClientUpdateResponseChunk {

beacon_node/http_api/tests/tests.rs

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2216,6 +2216,24 @@ impl ApiTester {
22162216
self
22172217
}
22182218

2219+
pub async fn test_get_beacon_light_client_updates_ssz(self) -> Self {
2220+
let current_epoch = self.chain.epoch().unwrap();
2221+
let current_sync_committee_period = current_epoch
2222+
.sync_committee_period(&self.chain.spec)
2223+
.unwrap();
2224+
2225+
match self
2226+
.client
2227+
.get_beacon_light_client_updates_ssz::<E>(current_sync_committee_period, 1)
2228+
.await
2229+
{
2230+
Ok(result) => result,
2231+
Err(e) => panic!("query failed incorrectly: {e:?}"),
2232+
};
2233+
2234+
self
2235+
}
2236+
22192237
pub async fn test_get_beacon_light_client_updates(self) -> Self {
22202238
let current_epoch = self.chain.epoch().unwrap();
22212239
let current_sync_committee_period = current_epoch
@@ -7073,6 +7091,8 @@ async fn get_light_client_updates() {
70737091
ApiTester::new_from_config(config)
70747092
.await
70757093
.test_get_beacon_light_client_updates()
7094+
.await
7095+
.test_get_beacon_light_client_updates_ssz()
70767096
.await;
70777097
}
70787098

common/eth2/src/lib.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -981,6 +981,32 @@ impl BeaconNodeHttpClient {
981981
})
982982
}
983983

984+
/// `GET beacon/light_client/updates`
985+
///
986+
/// Returns `Ok(None)` on a 404 error.
987+
pub async fn get_beacon_light_client_updates_ssz<E: EthSpec>(
988+
&self,
989+
start_period: u64,
990+
count: u64,
991+
) -> Result<Option<Vec<u8>>, Error> {
992+
let mut path = self.eth_path(V1)?;
993+
994+
path.path_segments_mut()
995+
.map_err(|()| Error::InvalidUrl(self.server.clone()))?
996+
.push("beacon")
997+
.push("light_client")
998+
.push("updates");
999+
1000+
path.query_pairs_mut()
1001+
.append_pair("start_period", &start_period.to_string());
1002+
1003+
path.query_pairs_mut()
1004+
.append_pair("count", &count.to_string());
1005+
1006+
self.get_bytes_opt_accept_header(path, Accept::Ssz, self.timeouts.default)
1007+
.await
1008+
}
1009+
9841010
/// `GET beacon/light_client/bootstrap`
9851011
///
9861012
/// Returns `Ok(None)` on a 404 error.

common/eth2/src/types.rs

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use multiaddr::Multiaddr;
1111
use reqwest::header::HeaderMap;
1212
use serde::{Deserialize, Deserializer, Serialize};
1313
use serde_utils::quoted_u64::Quoted;
14+
use ssz::Encode;
1415
use ssz::{Decode, DecodeError};
1516
use ssz_derive::{Decode, Encode};
1617
use std::fmt::{self, Display};
@@ -823,16 +824,32 @@ pub struct LightClientUpdatesQuery {
823824
pub count: u64,
824825
}
825826

826-
#[derive(Encode, Decode)]
827-
pub struct LightClientUpdateResponseChunk {
827+
pub struct LightClientUpdateResponseChunk<E: EthSpec> {
828828
pub response_chunk_len: u64,
829-
pub response_chunk: LightClientUpdateResponseChunkInner,
829+
pub response_chunk: LightClientUpdateResponseChunkInner<E>,
830830
}
831831

832-
#[derive(Encode, Decode)]
833-
pub struct LightClientUpdateResponseChunkInner {
832+
impl<E: EthSpec> Encode for LightClientUpdateResponseChunk<E> {
833+
fn is_ssz_fixed_len() -> bool {
834+
false
835+
}
836+
837+
fn ssz_bytes_len(&self) -> usize {
838+
0_u64.ssz_bytes_len()
839+
+ self.response_chunk.context.len()
840+
+ self.response_chunk.payload.ssz_bytes_len()
841+
}
842+
843+
fn ssz_append(&self, buf: &mut Vec<u8>) {
844+
buf.extend_from_slice(&self.response_chunk_len.to_le_bytes());
845+
buf.extend_from_slice(&self.response_chunk.context);
846+
self.response_chunk.payload.ssz_append(buf);
847+
}
848+
}
849+
850+
pub struct LightClientUpdateResponseChunkInner<E: EthSpec> {
834851
pub context: [u8; 4],
835-
pub payload: Vec<u8>,
852+
pub payload: LightClientUpdate<E>,
836853
}
837854

838855
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, Hash)]

0 commit comments

Comments
 (0)