Skip to content

Commit fa45915

Browse files
authored
refactor: refactor serialization for content key and values (ethereum#1128)
1 parent 56b7971 commit fa45915

File tree

16 files changed

+313
-337
lines changed

16 files changed

+313
-337
lines changed

ethportal-api/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ pub use types::{
4040
beacon::{BeaconContentValue, PossibleBeaconContentValue},
4141
error::ContentValueError,
4242
history::{HistoryContentValue, PossibleHistoryContentValue},
43+
state::{PossibleStateContentValue, StateContentValue},
4344
},
4445
execution::{block_body::*, header::*, receipts::*},
4546
};

ethportal-api/src/types/content_key/beacon.rs

Lines changed: 51 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,15 @@
11
use crate::{
22
types::content_key::{error::ContentKeyError, overlay::OverlayContentKey},
3-
utils::bytes::{hex_decode, hex_encode_compact},
3+
utils::bytes::hex_encode_compact,
44
};
5-
use serde::{de, Deserialize, Deserializer, Serialize, Serializer};
5+
use serde::{Deserialize, Deserializer, Serialize, Serializer};
66
use sha2::{Digest, Sha256};
77
use ssz::{Decode, DecodeError, Encode};
88
use ssz_derive::{Decode, Encode};
99
use std::fmt;
1010

1111
// Prefixes for the different types of beacon content keys:
12-
// https://github.com/ethereum/portal-network-specs/blob/72327da43c7a199ba2735344ef98f9121aef2f68/beacon-chain/beacon-network.md
12+
// https://github.com/ethereum/portal-network-specs/blob/638aca50c913a749d0d762264d9a4ac72f1a9966/beacon-chain/beacon-network.md
1313
pub const LIGHT_CLIENT_BOOTSTRAP_KEY_PREFIX: u8 = 0x10;
1414
pub const LIGHT_CLIENT_UPDATES_BY_RANGE_KEY_PREFIX: u8 = 0x11;
1515
pub const LIGHT_CLIENT_FINALITY_UPDATE_KEY_PREFIX: u8 = 0x12;
@@ -24,83 +24,6 @@ pub enum BeaconContentKey {
2424
LightClientOptimisticUpdate(LightClientOptimisticUpdateKey),
2525
}
2626

27-
impl Encode for BeaconContentKey {
28-
fn is_ssz_fixed_len() -> bool {
29-
false
30-
}
31-
32-
fn ssz_append(&self, buf: &mut Vec<u8>) {
33-
let bytes = self.to_bytes();
34-
buf.extend_from_slice(&bytes);
35-
}
36-
37-
fn ssz_bytes_len(&self) -> usize {
38-
self.to_bytes().len()
39-
}
40-
}
41-
42-
impl Decode for BeaconContentKey {
43-
fn is_ssz_fixed_len() -> bool {
44-
false
45-
}
46-
47-
fn from_ssz_bytes(bytes: &[u8]) -> Result<Self, DecodeError> {
48-
match bytes[0] {
49-
LIGHT_CLIENT_BOOTSTRAP_KEY_PREFIX => {
50-
let block_hash = <[u8; 32]>::try_from(&bytes[1..33]).map_err(|err| {
51-
DecodeError::BytesInvalid(format!(
52-
"Failed to decode LightClientBootstrapKey: {err:?}"
53-
))
54-
})?;
55-
Ok(Self::LightClientBootstrap(LightClientBootstrapKey {
56-
block_hash,
57-
}))
58-
}
59-
LIGHT_CLIENT_UPDATES_BY_RANGE_KEY_PREFIX => {
60-
let start_period = u64::from_ssz_bytes(&bytes[1..9]).map_err(|err| {
61-
DecodeError::BytesInvalid(format!(
62-
"Failed to decode LightClientUpdatesByRangeKey: {err:?}"
63-
))
64-
})?;
65-
let count = u64::from_ssz_bytes(&bytes[9..17]).map_err(|err| {
66-
DecodeError::BytesInvalid(format!(
67-
"Failed to decode LightClientUpdatesByRangeKey: {err:?}"
68-
))
69-
})?;
70-
Ok(Self::LightClientUpdatesByRange(
71-
LightClientUpdatesByRangeKey {
72-
start_period,
73-
count,
74-
},
75-
))
76-
}
77-
LIGHT_CLIENT_FINALITY_UPDATE_KEY_PREFIX => {
78-
let finalized_slot = u64::from_ssz_bytes(&bytes[1..9]).map_err(|err| {
79-
DecodeError::BytesInvalid(format!(
80-
"Failed to decode LightClientFinalityUpdateKey: {err:?}",
81-
))
82-
})?;
83-
Ok(Self::LightClientFinalityUpdate(
84-
LightClientFinalityUpdateKey::new(finalized_slot),
85-
))
86-
}
87-
LIGHT_CLIENT_OPTIMISTIC_UPDATE_KEY_PREFIX => {
88-
let signature_slot = u64::from_ssz_bytes(&bytes[1..9]).map_err(|err| {
89-
DecodeError::BytesInvalid(format!(
90-
"Failed to decode LightClientOptimisticUpdateKey: {err:?}",
91-
))
92-
})?;
93-
Ok(Self::LightClientOptimisticUpdate(
94-
LightClientOptimisticUpdateKey::new(signature_slot),
95-
))
96-
}
97-
_ => Err(DecodeError::BytesInvalid(format!(
98-
"Failed to decode BeaconContentKey, Unexpected union selector byte: {bytes:?}",
99-
))),
100-
}
101-
}
102-
}
103-
10427
/// Key used to identify a light client bootstrap.
10528
#[derive(Clone, Debug, Decode, Encode, Eq, PartialEq)]
10629
pub struct LightClientBootstrapKey {
@@ -145,22 +68,50 @@ impl LightClientOptimisticUpdateKey {
14568

14669
impl From<&BeaconContentKey> for Vec<u8> {
14770
fn from(val: &BeaconContentKey) -> Self {
148-
val.as_ssz_bytes()
71+
val.to_bytes()
14972
}
15073
}
15174

15275
impl From<BeaconContentKey> for Vec<u8> {
15376
fn from(val: BeaconContentKey) -> Self {
154-
val.as_ssz_bytes()
77+
val.to_bytes()
15578
}
15679
}
15780

15881
impl TryFrom<Vec<u8>> for BeaconContentKey {
15982
type Error = ContentKeyError;
16083

16184
fn try_from(value: Vec<u8>) -> Result<Self, Self::Error> {
162-
BeaconContentKey::from_ssz_bytes(&value)
163-
.map_err(|e| ContentKeyError::from_decode_error(e, value))
85+
let Some((&selector, key)) = value.split_first() else {
86+
return Err(ContentKeyError::InvalidLength {
87+
received: value.len(),
88+
expected: 1,
89+
});
90+
};
91+
match selector {
92+
LIGHT_CLIENT_BOOTSTRAP_KEY_PREFIX => LightClientBootstrapKey::from_ssz_bytes(key)
93+
.map(Self::LightClientBootstrap)
94+
.map_err(|e| ContentKeyError::from_decode_error(e, value)),
95+
LIGHT_CLIENT_UPDATES_BY_RANGE_KEY_PREFIX => {
96+
LightClientUpdatesByRangeKey::from_ssz_bytes(key)
97+
.map(Self::LightClientUpdatesByRange)
98+
.map_err(|e| ContentKeyError::from_decode_error(e, value))
99+
}
100+
LIGHT_CLIENT_FINALITY_UPDATE_KEY_PREFIX => {
101+
LightClientFinalityUpdateKey::from_ssz_bytes(key)
102+
.map(Self::LightClientFinalityUpdate)
103+
.map_err(|e| ContentKeyError::from_decode_error(e, value))
104+
}
105+
LIGHT_CLIENT_OPTIMISTIC_UPDATE_KEY_PREFIX => {
106+
LightClientOptimisticUpdateKey::from_ssz_bytes(key)
107+
.map(Self::LightClientOptimisticUpdate)
108+
.map_err(|e| ContentKeyError::from_decode_error(e, value))
109+
}
110+
_ => Err(ContentKeyError::from_decode_error(
111+
DecodeError::UnionSelectorInvalid(selector),
112+
value,
113+
)),
114+
}
164115
}
165116
}
166117

@@ -192,7 +143,7 @@ impl fmt::Display for BeaconContentKey {
192143
impl OverlayContentKey for BeaconContentKey {
193144
fn content_id(&self) -> [u8; 32] {
194145
let mut sha256 = Sha256::new();
195-
sha256.update(self.as_ssz_bytes());
146+
sha256.update(self.to_bytes());
196147
sha256.finalize().into()
197148
}
198149

@@ -202,20 +153,19 @@ impl OverlayContentKey for BeaconContentKey {
202153
match self {
203154
BeaconContentKey::LightClientBootstrap(key) => {
204155
bytes.push(LIGHT_CLIENT_BOOTSTRAP_KEY_PREFIX);
205-
bytes.extend_from_slice(&key.block_hash);
156+
bytes.extend_from_slice(&key.as_ssz_bytes());
206157
}
207158
BeaconContentKey::LightClientUpdatesByRange(key) => {
208159
bytes.push(LIGHT_CLIENT_UPDATES_BY_RANGE_KEY_PREFIX);
209-
bytes.extend_from_slice(&key.start_period.as_ssz_bytes());
210-
bytes.extend_from_slice(&key.count.as_ssz_bytes());
160+
bytes.extend_from_slice(&key.as_ssz_bytes());
211161
}
212162
BeaconContentKey::LightClientFinalityUpdate(key) => {
213163
bytes.push(LIGHT_CLIENT_FINALITY_UPDATE_KEY_PREFIX);
214-
bytes.extend_from_slice(&key.finalized_slot.as_ssz_bytes())
164+
bytes.extend_from_slice(&key.as_ssz_bytes())
215165
}
216166
BeaconContentKey::LightClientOptimisticUpdate(key) => {
217167
bytes.push(LIGHT_CLIENT_OPTIMISTIC_UPDATE_KEY_PREFIX);
218-
bytes.extend_from_slice(&key.signature_slot.as_ssz_bytes())
168+
bytes.extend_from_slice(&key.as_ssz_bytes())
219169
}
220170
}
221171

@@ -237,31 +187,21 @@ impl<'de> Deserialize<'de> for BeaconContentKey {
237187
where
238188
D: Deserializer<'de>,
239189
{
240-
let data = String::deserialize(deserializer)?.to_lowercase();
241-
242-
if !data.starts_with("0x") {
243-
return Err(de::Error::custom(format!(
244-
"Hex strings must start with 0x, but found {}",
245-
&data[..2]
246-
)));
247-
}
248-
249-
let ssz_bytes = hex_decode(&data).map_err(de::Error::custom)?;
250-
251-
Self::from_ssz_bytes(&ssz_bytes)
252-
.map_err(|e| ContentKeyError::from_decode_error(e, ssz_bytes))
253-
.map_err(serde::de::Error::custom)
190+
let s = String::deserialize(deserializer)?;
191+
Self::from_hex(&s).map_err(serde::de::Error::custom)
254192
}
255193
}
256194

257195
#[cfg(test)]
258196
#[allow(clippy::unwrap_used)]
259197
mod test {
198+
use crate::utils::bytes::hex_decode;
199+
260200
use super::*;
261201

262-
fn test_ssz_encode_decode(content_key: &BeaconContentKey) {
263-
let ssz_bytes = content_key.as_ssz_bytes();
264-
let decoded_key = BeaconContentKey::from_ssz_bytes(&ssz_bytes).unwrap();
202+
fn test_encode_decode(content_key: &BeaconContentKey) {
203+
let bytes = content_key.to_bytes();
204+
let decoded_key = BeaconContentKey::try_from(bytes).unwrap();
265205
assert_eq!(*content_key, decoded_key);
266206
}
267207

@@ -281,7 +221,7 @@ mod test {
281221

282222
let content_key = BeaconContentKey::LightClientBootstrap(bootstrap);
283223

284-
test_ssz_encode_decode(&content_key);
224+
test_encode_decode(&content_key);
285225

286226
assert_eq!(content_key.to_bytes(), expected_content_key);
287227
assert_eq!(
@@ -306,7 +246,7 @@ mod test {
306246

307247
let content_key = BeaconContentKey::LightClientUpdatesByRange(content_key);
308248

309-
test_ssz_encode_decode(&content_key);
249+
test_encode_decode(&content_key);
310250

311251
assert_eq!(content_key.to_bytes(), expected_content_key);
312252
assert_eq!(
@@ -323,7 +263,7 @@ mod test {
323263
let content_key =
324264
BeaconContentKey::LightClientFinalityUpdate(LightClientFinalityUpdateKey::new(7271362));
325265

326-
test_ssz_encode_decode(&content_key);
266+
test_encode_decode(&content_key);
327267

328268
assert_eq!(content_key.to_bytes(), expected_content_key);
329269
assert_eq!(
@@ -341,7 +281,7 @@ mod test {
341281
LightClientOptimisticUpdateKey::new(7271362),
342282
);
343283

344-
test_ssz_encode_decode(&content_key);
284+
test_encode_decode(&content_key);
345285

346286
assert_eq!(content_key.to_bytes(), expected_content_key);
347287
assert_eq!(

0 commit comments

Comments
 (0)