mirror of
https://github.com/sigp/lighthouse.git
synced 2026-05-07 00:42:42 +00:00
Add optimized SSZ decoding for fixed-len items (#865)
* Add custom SSZ decode for Validator * Move efficient decode into macro * Don't allocate SSZ offset to heap * Use smallvec in SszDecoder * Fix test compile error
This commit is contained in:
@@ -14,3 +14,4 @@ eth2_ssz_derive = "0.1.0"
|
||||
|
||||
[dependencies]
|
||||
ethereum-types = "0.8.0"
|
||||
smallvec = "1.2.0"
|
||||
|
||||
@@ -1,4 +1,7 @@
|
||||
use super::*;
|
||||
use smallvec::{smallvec, SmallVec};
|
||||
|
||||
type SmallVec8<T> = SmallVec<[T; 8]>;
|
||||
|
||||
pub mod impls;
|
||||
|
||||
@@ -62,8 +65,8 @@ pub struct Offset {
|
||||
/// See [`SszDecoder`](struct.SszDecoder.html) for usage examples.
|
||||
pub struct SszDecoderBuilder<'a> {
|
||||
bytes: &'a [u8],
|
||||
items: Vec<&'a [u8]>,
|
||||
offsets: Vec<Offset>,
|
||||
items: SmallVec8<&'a [u8]>,
|
||||
offsets: SmallVec8<Offset>,
|
||||
items_index: usize,
|
||||
}
|
||||
|
||||
@@ -73,8 +76,8 @@ impl<'a> SszDecoderBuilder<'a> {
|
||||
pub fn new(bytes: &'a [u8]) -> Self {
|
||||
Self {
|
||||
bytes,
|
||||
items: vec![],
|
||||
offsets: vec![],
|
||||
items: smallvec![],
|
||||
offsets: smallvec![],
|
||||
items_index: 0,
|
||||
}
|
||||
}
|
||||
@@ -204,7 +207,7 @@ impl<'a> SszDecoderBuilder<'a> {
|
||||
///
|
||||
/// ```
|
||||
pub struct SszDecoder<'a> {
|
||||
items: Vec<&'a [u8]>,
|
||||
items: SmallVec8<&'a [u8]>,
|
||||
}
|
||||
|
||||
impl<'a> SszDecoder<'a> {
|
||||
|
||||
@@ -115,7 +115,7 @@ impl<'a> SszEncoder<'a> {
|
||||
item.ssz_append(&mut self.buf);
|
||||
} else {
|
||||
self.buf
|
||||
.append(&mut encode_length(self.offset + self.variable_bytes.len()));
|
||||
.extend_from_slice(&encode_length(self.offset + self.variable_bytes.len()));
|
||||
|
||||
item.ssz_append(&mut self.variable_bytes);
|
||||
}
|
||||
@@ -132,17 +132,17 @@ impl<'a> SszEncoder<'a> {
|
||||
}
|
||||
}
|
||||
|
||||
/// Encode `index` as a little-endian byte vec of `BYTES_PER_LENGTH_OFFSET` length.
|
||||
/// Encode `index` as a little-endian byte array of `BYTES_PER_LENGTH_OFFSET` length.
|
||||
///
|
||||
/// If `len` is larger than `2 ^ BYTES_PER_LENGTH_OFFSET`, a `debug_assert` is raised.
|
||||
pub fn encode_union_index(index: usize) -> Vec<u8> {
|
||||
pub fn encode_union_index(index: usize) -> [u8; BYTES_PER_LENGTH_OFFSET] {
|
||||
encode_length(index)
|
||||
}
|
||||
|
||||
/// Encode `len` as a little-endian byte vec of `BYTES_PER_LENGTH_OFFSET` length.
|
||||
/// Encode `len` as a little-endian byte array of `BYTES_PER_LENGTH_OFFSET` length.
|
||||
///
|
||||
/// If `len` is larger than `2 ^ BYTES_PER_LENGTH_OFFSET`, a `debug_assert` is raised.
|
||||
pub fn encode_length(len: usize) -> Vec<u8> {
|
||||
pub fn encode_length(len: usize) -> [u8; BYTES_PER_LENGTH_OFFSET] {
|
||||
// Note: it is possible for `len` to be larger than what can be encoded in
|
||||
// `BYTES_PER_LENGTH_OFFSET` bytes, triggering this debug assertion.
|
||||
//
|
||||
@@ -166,7 +166,9 @@ pub fn encode_length(len: usize) -> Vec<u8> {
|
||||
// If you have a different opinion, feel free to start an issue and tag @paulhauner.
|
||||
debug_assert!(len <= MAX_LENGTH_VALUE);
|
||||
|
||||
len.to_le_bytes()[0..BYTES_PER_LENGTH_OFFSET].to_vec()
|
||||
let mut bytes = [0; BYTES_PER_LENGTH_OFFSET];
|
||||
bytes.copy_from_slice(&len.to_le_bytes()[0..BYTES_PER_LENGTH_OFFSET]);
|
||||
bytes
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
@@ -175,13 +177,13 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_encode_length() {
|
||||
assert_eq!(encode_length(0), vec![0; 4]);
|
||||
assert_eq!(encode_length(0), [0; 4]);
|
||||
|
||||
assert_eq!(encode_length(1), vec![1, 0, 0, 0]);
|
||||
assert_eq!(encode_length(1), [1, 0, 0, 0]);
|
||||
|
||||
assert_eq!(
|
||||
encode_length(MAX_LENGTH_VALUE),
|
||||
vec![255; BYTES_PER_LENGTH_OFFSET]
|
||||
[255; BYTES_PER_LENGTH_OFFSET]
|
||||
);
|
||||
}
|
||||
|
||||
@@ -195,6 +197,6 @@ mod tests {
|
||||
#[test]
|
||||
#[cfg(not(debug_assertions))]
|
||||
fn test_encode_length_above_max_not_debug_does_not_panic() {
|
||||
assert_eq!(encode_length(MAX_LENGTH_VALUE + 1), vec![0; 4]);
|
||||
assert_eq!(&encode_length(MAX_LENGTH_VALUE + 1)[..], &[0; 4]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -221,9 +221,9 @@ impl<T: Encode> Encode for Option<T> {
|
||||
|
||||
fn ssz_append(&self, buf: &mut Vec<u8>) {
|
||||
match self {
|
||||
None => buf.append(&mut encode_union_index(0)),
|
||||
None => buf.extend_from_slice(&encode_union_index(0)),
|
||||
Some(t) => {
|
||||
buf.append(&mut encode_union_index(1));
|
||||
buf.extend_from_slice(&encode_union_index(1));
|
||||
t.ssz_append(buf);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user