mirror of
https://github.com/paradigmxyz/reth.git
synced 2026-02-19 03:04:27 -05:00
perf: use stack-allocated [u8; 65] for StoredNibblesSubKey encoding (#22314)
Co-authored-by: Amp <amp@ampcode.com> Co-authored-by: Matthias Seitz <matthias.seitz@outlook.de>
This commit is contained in:
5
.changelog/proud-crabs-bark.md
Normal file
5
.changelog/proud-crabs-bark.md
Normal file
@@ -0,0 +1,5 @@
|
||||
---
|
||||
reth-db-api: patch
|
||||
---
|
||||
|
||||
Changed `StoredNibblesSubKey` encoding to use a stack-allocated `[u8; 65]` array instead of a heap-allocated `Vec<u8>`, avoiding unnecessary heap allocation.
|
||||
@@ -138,13 +138,10 @@ impl Decode for StoredNibbles {
|
||||
}
|
||||
|
||||
impl Encode for StoredNibblesSubKey {
|
||||
type Encoded = Vec<u8>;
|
||||
type Encoded = [u8; 65];
|
||||
|
||||
// Delegate to the Compact implementation
|
||||
fn encode(self) -> Self::Encoded {
|
||||
let mut buf = Vec::with_capacity(65);
|
||||
self.to_compact(&mut buf);
|
||||
buf
|
||||
self.to_compact_array()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -90,6 +90,22 @@ impl From<StoredNibblesSubKey> for Nibbles {
|
||||
}
|
||||
}
|
||||
|
||||
impl StoredNibblesSubKey {
|
||||
/// Encodes the nibbles into a fixed-size `[u8; 65]` array.
|
||||
///
|
||||
/// The first 64 bytes contain the nibble values (right-padded with zeros),
|
||||
/// and the 65th byte stores the actual nibble count.
|
||||
pub fn to_compact_array(&self) -> [u8; 65] {
|
||||
assert!(self.0.len() <= 64);
|
||||
let mut buf = [0u8; 65];
|
||||
for (i, nibble) in self.0.iter().enumerate() {
|
||||
buf[i] = nibble;
|
||||
}
|
||||
buf[64] = self.0.len() as u8;
|
||||
buf
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(any(test, feature = "reth-codec"))]
|
||||
impl reth_codecs::Compact for StoredNibblesSubKey {
|
||||
fn to_compact<B>(&self, buf: &mut B) -> usize
|
||||
@@ -187,4 +203,51 @@ mod tests {
|
||||
let deserialized: StoredNibblesSubKey = serde_json::from_str(&serialized).unwrap();
|
||||
assert_eq!(subkey, deserialized);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_stored_nibbles_subkey_compact_array_empty() {
|
||||
let subkey = StoredNibblesSubKey::from(vec![]);
|
||||
let arr = subkey.to_compact_array();
|
||||
assert_eq!(arr, [0u8; 65]);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_stored_nibbles_subkey_compact_array_full() {
|
||||
let nibbles: Vec<u8> = (0..64).map(|i| i % 16).collect();
|
||||
let subkey = StoredNibblesSubKey::from(nibbles.clone());
|
||||
let arr = subkey.to_compact_array();
|
||||
assert_eq!(&arr[..64], &nibbles[..]);
|
||||
assert_eq!(arr[64], 64);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_stored_nibbles_subkey_compact_array_roundtrip() {
|
||||
let subkey = StoredNibblesSubKey::from(vec![0x0A, 0x0B, 0x0C]);
|
||||
let arr = subkey.to_compact_array();
|
||||
let (recovered, rest) = StoredNibblesSubKey::from_compact(&arr, 65);
|
||||
assert_eq!(recovered, subkey);
|
||||
assert!(rest.is_empty());
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_stored_nibbles_subkey_compact_array_matches_to_compact() {
|
||||
for len in [0, 1, 2, 31, 32, 33, 63, 64] {
|
||||
let nibbles: Vec<u8> = (0..len).map(|i| (i % 16) as u8).collect();
|
||||
let subkey = StoredNibblesSubKey::from(nibbles);
|
||||
|
||||
let arr = subkey.to_compact_array();
|
||||
|
||||
let mut compact_buf = BytesMut::with_capacity(65);
|
||||
subkey.to_compact(&mut compact_buf);
|
||||
|
||||
assert_eq!(&arr[..], &compact_buf[..], "mismatch at nibble length {len}");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_stored_nibbles_subkey_compact_array_padding_is_zero() {
|
||||
let subkey = StoredNibblesSubKey::from(vec![0x0F; 10]);
|
||||
let arr = subkey.to_compact_array();
|
||||
assert!(arr[10..64].iter().all(|&b| b == 0), "padding bytes must be zero");
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user