chore: replace StoredBranchNode, StoredTrieMask and StoredHashBuilderValue types with Compact impl instead (#9573)

This commit is contained in:
joshieDo
2024-07-17 14:06:05 +02:00
committed by GitHub
parent 0befab52c9
commit 89d0281ce3
20 changed files with 175 additions and 206 deletions

1
Cargo.lock generated
View File

@ -6575,6 +6575,7 @@ dependencies = [
"alloy-eips",
"alloy-genesis",
"alloy-primitives",
"alloy-trie",
"arbitrary",
"bytes",
"modular-bitfield",

View File

@ -19,6 +19,7 @@ alloy-consensus = { workspace = true, optional = true }
alloy-eips = { workspace = true, optional = true }
alloy-genesis = { workspace = true, optional = true }
alloy-primitives.workspace = true
alloy-trie.workspace = true
# misc
bytes.workspace = true

View File

@ -3,5 +3,6 @@ mod authorization_list;
mod genesis_account;
mod log;
mod request;
mod trie;
mod txkind;
mod withdrawal;

View File

@ -0,0 +1,138 @@
//! Native Compact codec impl for EIP-7685 requests.
use crate::Compact;
use alloy_primitives::B256;
use alloy_trie::{hash_builder::HashBuilderValue, BranchNodeCompact, TrieMask};
use bytes::{Buf, BufMut};
impl Compact for HashBuilderValue {
fn to_compact<B>(self, buf: &mut B) -> usize
where
B: BufMut + AsMut<[u8]>,
{
match self {
Self::Hash(hash) => {
buf.put_u8(0);
1 + hash.to_compact(buf)
}
Self::Bytes(bytes) => {
buf.put_u8(1);
1 + bytes.to_compact(buf)
}
}
}
// # Panics
//
// A panic will be triggered if a HashBuilderValue variant greater than 1 is passed from the
// database.
fn from_compact(mut buf: &[u8], _: usize) -> (Self, &[u8]) {
match buf.get_u8() {
0 => {
let (hash, buf) = B256::from_compact(buf, 32);
(Self::Hash(hash), buf)
}
1 => {
let (bytes, buf) = Vec::from_compact(buf, 0);
(Self::Bytes(bytes), buf)
}
_ => unreachable!("Junk data in database: unknown HashBuilderValue variant"),
}
}
}
impl Compact for BranchNodeCompact {
fn to_compact<B>(self, buf: &mut B) -> usize
where
B: bytes::BufMut + AsMut<[u8]>,
{
let mut buf_size = 0;
buf_size += self.state_mask.to_compact(buf);
buf_size += self.tree_mask.to_compact(buf);
buf_size += self.hash_mask.to_compact(buf);
if let Some(root_hash) = self.root_hash {
buf_size += B256::len_bytes();
buf.put_slice(root_hash.as_slice());
}
for hash in &self.hashes {
buf_size += B256::len_bytes();
buf.put_slice(hash.as_slice());
}
buf_size
}
fn from_compact(buf: &[u8], _len: usize) -> (Self, &[u8]) {
let hash_len = B256::len_bytes();
// Assert the buffer is long enough to contain the masks and the hashes.
assert_eq!(buf.len() % hash_len, 6);
// Consume the masks.
let (state_mask, buf) = TrieMask::from_compact(buf, 0);
let (tree_mask, buf) = TrieMask::from_compact(buf, 0);
let (hash_mask, buf) = TrieMask::from_compact(buf, 0);
let mut buf = buf;
let mut num_hashes = buf.len() / hash_len;
let mut root_hash = None;
// Check if the root hash is present
if hash_mask.count_ones() as usize + 1 == num_hashes {
root_hash = Some(B256::from_slice(&buf[..hash_len]));
buf.advance(hash_len);
num_hashes -= 1;
}
// Consume all remaining hashes.
let mut hashes = Vec::<B256>::with_capacity(num_hashes);
for _ in 0..num_hashes {
hashes.push(B256::from_slice(&buf[..hash_len]));
buf.advance(hash_len);
}
(Self::new(state_mask, tree_mask, hash_mask, hashes, root_hash), buf)
}
}
impl Compact for TrieMask {
fn to_compact<B>(self, buf: &mut B) -> usize
where
B: bytes::BufMut + AsMut<[u8]>,
{
buf.put_u16(self.get());
2
}
fn from_compact(mut buf: &[u8], _len: usize) -> (Self, &[u8]) {
let mask = buf.get_u16();
(Self::new(mask), buf)
}
}
#[cfg(test)]
mod tests {
use super::*;
use alloy_primitives::hex;
#[test]
fn node_encoding() {
let n = BranchNodeCompact::new(
0xf607,
0x0005,
0x4004,
vec![
hex!("90d53cd810cc5d4243766cd4451e7b9d14b736a1148b26b3baac7617f617d321").into(),
hex!("cc35c964dda53ba6c0b87798073a9628dbc9cd26b5cce88eb69655a9c609caf1").into(),
],
Some(hex!("aaaabbbb0006767767776fffffeee44444000005567645600000000eeddddddd").into()),
);
let mut out = Vec::new();
let compact_len = n.clone().to_compact(&mut out);
assert_eq!(BranchNodeCompact::from_compact(&out, compact_len).0, n);
}
}

View File

@ -208,7 +208,7 @@ impl_compression_for_compact!(
Receipt,
TxType,
StorageEntry,
StoredBranchNode,
BranchNodeCompact,
StoredNibbles,
StoredNibblesSubKey,
StorageTrieEntry,

View File

@ -35,7 +35,7 @@ use reth_primitives::{
use reth_primitives_traits::IntegerList;
use reth_prune_types::{PruneCheckpoint, PruneSegment};
use reth_stages_types::StageCheckpoint;
use reth_trie_common::{StorageTrieEntry, StoredBranchNode, StoredNibbles, StoredNibblesSubKey};
use reth_trie_common::{BranchNodeCompact, StorageTrieEntry, StoredNibbles, StoredNibblesSubKey};
use serde::{Deserialize, Serialize};
use std::fmt;
@ -381,7 +381,7 @@ tables! {
table HashedStorages<Key = B256, Value = StorageEntry, SubKey = B256>;
/// Stores the current state's Merkle Patricia Tree.
table AccountsTrie<Key = StoredNibbles, Value = StoredBranchNode>;
table AccountsTrie<Key = StoredNibbles, Value = BranchNodeCompact>;
/// From HashedAddress => NibblesSubKey => Intermediate value
table StoragesTrie<Key = B256, Value = StorageTrieEntry, SubKey = StoredNibblesSubKey>;

View File

@ -3,7 +3,4 @@
mod state;
pub use state::HashBuilderState;
mod value;
pub(crate) use value::StoredHashBuilderValue;
pub use alloy_trie::hash_builder::*;

View File

@ -1,5 +1,4 @@
use super::StoredHashBuilderValue;
use crate::{StoredTrieMask, TrieMask};
use crate::TrieMask;
use alloy_trie::{hash_builder::HashBuilderValue, HashBuilder};
use bytes::Buf;
use nybbles::Nibbles;
@ -77,24 +76,24 @@ impl Compact for HashBuilderState {
len += 2 + item.len();
}
len += StoredHashBuilderValue(self.value).to_compact(buf);
len += self.value.to_compact(buf);
buf.put_u16(self.groups.len() as u16);
len += 2;
for item in &self.groups {
len += StoredTrieMask(*item).to_compact(buf);
len += (*item).to_compact(buf);
}
buf.put_u16(self.tree_masks.len() as u16);
len += 2;
for item in &self.tree_masks {
len += StoredTrieMask(*item).to_compact(buf);
len += (*item).to_compact(buf);
}
buf.put_u16(self.hash_masks.len() as u16);
len += 2;
for item in &self.hash_masks {
len += StoredTrieMask(*item).to_compact(buf);
len += (*item).to_compact(buf);
}
buf.put_u8(self.stored_in_database as u8);
@ -113,12 +112,12 @@ impl Compact for HashBuilderState {
buf.advance(item_len);
}
let (StoredHashBuilderValue(value), mut buf) = StoredHashBuilderValue::from_compact(buf, 0);
let (value, mut buf) = HashBuilderValue::from_compact(buf, 0);
let groups_len = buf.get_u16() as usize;
let mut groups = Vec::with_capacity(groups_len);
for _ in 0..groups_len {
let (StoredTrieMask(item), rest) = StoredTrieMask::from_compact(buf, 0);
let (item, rest) = TrieMask::from_compact(buf, 0);
groups.push(item);
buf = rest;
}
@ -126,7 +125,7 @@ impl Compact for HashBuilderState {
let tree_masks_len = buf.get_u16() as usize;
let mut tree_masks = Vec::with_capacity(tree_masks_len);
for _ in 0..tree_masks_len {
let (StoredTrieMask(item), rest) = StoredTrieMask::from_compact(buf, 0);
let (item, rest) = TrieMask::from_compact(buf, 0);
tree_masks.push(item);
buf = rest;
}
@ -134,7 +133,7 @@ impl Compact for HashBuilderState {
let hash_masks_len = buf.get_u16() as usize;
let mut hash_masks = Vec::with_capacity(hash_masks_len);
for _ in 0..hash_masks_len {
let (StoredTrieMask(item), rest) = StoredTrieMask::from_compact(buf, 0);
let (item, rest) = TrieMask::from_compact(buf, 0);
hash_masks.push(item);
buf = rest;
}

View File

@ -1,43 +0,0 @@
use alloy_primitives::B256;
use alloy_trie::hash_builder::HashBuilderValue;
use bytes::Buf;
use reth_codecs::Compact;
/// A wrapper around `HashBuilderValue` that implements `Compact`.
pub(crate) struct StoredHashBuilderValue(pub(crate) HashBuilderValue);
impl Compact for StoredHashBuilderValue {
fn to_compact<B>(self, buf: &mut B) -> usize
where
B: bytes::BufMut + AsMut<[u8]>,
{
match self.0 {
HashBuilderValue::Hash(hash) => {
buf.put_u8(0);
1 + hash.to_compact(buf)
}
HashBuilderValue::Bytes(bytes) => {
buf.put_u8(1);
1 + bytes.to_compact(buf)
}
}
}
// # Panics
//
// A panic will be triggered if a HashBuilderValue variant greater than 1 is passed from the
// database.
fn from_compact(mut buf: &[u8], _len: usize) -> (Self, &[u8]) {
match buf.get_u8() {
0 => {
let (hash, buf) = B256::from_compact(buf, 32);
(Self(HashBuilderValue::Hash(hash)), buf)
}
1 => {
let (bytes, buf) = Vec::from_compact(buf, 0);
(Self(HashBuilderValue::Bytes(bytes)), buf)
}
_ => unreachable!("Junk data in database: unknown HashBuilderValue variant"),
}
}
}

View File

@ -14,15 +14,9 @@ pub mod hash_builder;
mod account;
pub use account::TrieAccount;
mod mask;
pub(crate) use mask::StoredTrieMask;
mod nibbles;
pub use nibbles::{Nibbles, StoredNibbles, StoredNibblesSubKey};
pub mod nodes;
pub use nodes::StoredBranchNode;
mod storage;
pub use storage::StorageTrieEntry;
@ -36,4 +30,4 @@ pub use proofs::{AccountProof, StorageProof};
pub mod root;
pub use alloy_trie::{proof, BranchNodeCompact, HashBuilder, TrieMask, EMPTY_ROOT_HASH};
pub use alloy_trie::{nodes::*, proof, BranchNodeCompact, HashBuilder, TrieMask, EMPTY_ROOT_HASH};

View File

@ -1,20 +0,0 @@
use super::TrieMask;
use bytes::Buf;
use reth_codecs::Compact;
pub(crate) struct StoredTrieMask(pub(crate) TrieMask);
impl Compact for StoredTrieMask {
fn to_compact<B>(self, buf: &mut B) -> usize
where
B: bytes::BufMut + AsMut<[u8]>,
{
buf.put_u16(self.0.get());
2
}
fn from_compact(mut buf: &[u8], _len: usize) -> (Self, &[u8]) {
let mask = buf.get_u16();
(Self(TrieMask::new(mask)), buf)
}
}

View File

@ -1,93 +0,0 @@
use crate::StoredTrieMask;
use alloy_primitives::B256;
use alloy_trie::BranchNodeCompact;
use bytes::Buf;
use reth_codecs::Compact;
use serde::{Deserialize, Serialize};
/// Wrapper around `BranchNodeCompact` that implements `Compact`.
#[derive(Debug, PartialEq, Eq, Serialize, Deserialize)]
pub struct StoredBranchNode(pub BranchNodeCompact);
impl Compact for StoredBranchNode {
fn to_compact<B>(self, buf: &mut B) -> usize
where
B: bytes::BufMut + AsMut<[u8]>,
{
let BranchNodeCompact { state_mask, tree_mask, hash_mask, root_hash, hashes } = self.0;
let mut buf_size = 0;
buf_size += StoredTrieMask(state_mask).to_compact(buf);
buf_size += StoredTrieMask(tree_mask).to_compact(buf);
buf_size += StoredTrieMask(hash_mask).to_compact(buf);
if let Some(root_hash) = root_hash {
buf_size += B256::len_bytes();
buf.put_slice(root_hash.as_slice());
}
for hash in &hashes {
buf_size += B256::len_bytes();
buf.put_slice(hash.as_slice());
}
buf_size
}
fn from_compact(buf: &[u8], _len: usize) -> (Self, &[u8]) {
let hash_len = B256::len_bytes();
// Assert the buffer is long enough to contain the masks and the hashes.
assert_eq!(buf.len() % hash_len, 6);
// Consume the masks.
let (StoredTrieMask(state_mask), buf) = StoredTrieMask::from_compact(buf, 0);
let (StoredTrieMask(tree_mask), buf) = StoredTrieMask::from_compact(buf, 0);
let (StoredTrieMask(hash_mask), buf) = StoredTrieMask::from_compact(buf, 0);
let mut buf = buf;
let mut num_hashes = buf.len() / hash_len;
let mut root_hash = None;
// Check if the root hash is present
if hash_mask.count_ones() as usize + 1 == num_hashes {
root_hash = Some(B256::from_slice(&buf[..hash_len]));
buf.advance(hash_len);
num_hashes -= 1;
}
// Consume all remaining hashes.
let mut hashes = Vec::<B256>::with_capacity(num_hashes);
for _ in 0..num_hashes {
hashes.push(B256::from_slice(&buf[..hash_len]));
buf.advance(hash_len);
}
(Self(BranchNodeCompact::new(state_mask, tree_mask, hash_mask, hashes, root_hash)), buf)
}
}
#[cfg(test)]
mod tests {
use super::*;
use alloy_primitives::hex;
#[test]
fn node_encoding() {
let n = BranchNodeCompact::new(
0xf607,
0x0005,
0x4004,
vec![
hex!("90d53cd810cc5d4243766cd4451e7b9d14b736a1148b26b3baac7617f617d321").into(),
hex!("cc35c964dda53ba6c0b87798073a9628dbc9cd26b5cce88eb69655a9c609caf1").into(),
],
Some(hex!("aaaabbbb0006767767776fffffeee44444000005567645600000000eeddddddd").into()),
);
let mut out = Vec::new();
let compact_len = StoredBranchNode(n.clone()).to_compact(&mut out);
assert_eq!(StoredBranchNode::from_compact(&out, compact_len).0 .0, n);
}
}

View File

@ -1,6 +0,0 @@
//! Various branch nodes produced by the hash builder.
mod branch;
pub use branch::StoredBranchNode;
pub use alloy_trie::nodes::*;

View File

@ -1,4 +1,4 @@
use super::{BranchNodeCompact, StoredBranchNode, StoredNibblesSubKey};
use super::{BranchNodeCompact, StoredNibblesSubKey};
use reth_codecs::Compact;
use serde::{Deserialize, Serialize};
@ -20,14 +20,14 @@ impl Compact for StorageTrieEntry {
B: bytes::BufMut + AsMut<[u8]>,
{
let nibbles_len = self.nibbles.to_compact(buf);
let node_len = StoredBranchNode(self.node).to_compact(buf);
let node_len = self.node.to_compact(buf);
nibbles_len + node_len
}
fn from_compact(buf: &[u8], len: usize) -> (Self, &[u8]) {
let (nibbles, buf) = StoredNibblesSubKey::from_compact(buf, 33);
let (node, buf) = StoredBranchNode::from_compact(buf, len - 33);
let this = Self { nibbles, node: node.0 };
let (node, buf) = BranchNodeCompact::from_compact(buf, len - 33);
let this = Self { nibbles, node };
(this, buf)
}
}

View File

@ -1,4 +1,4 @@
use super::{BranchNodeCompact, StoredBranchNode};
use super::BranchNodeCompact;
use bytes::Buf;
use reth_codecs::Compact;
@ -36,7 +36,7 @@ impl Compact for StoredSubNode {
if let Some(node) = self.node {
buf.put_u8(1);
len += 1;
len += StoredBranchNode(node).to_compact(buf);
len += node.to_compact(buf);
} else {
len += 1;
buf.put_u8(0);
@ -55,9 +55,9 @@ impl Compact for StoredSubNode {
let node_exists = buf.get_u8() != 0;
let node = if node_exists {
let (node, rest) = StoredBranchNode::from_compact(buf, 0);
let (node, rest) = BranchNodeCompact::from_compact(buf, 0);
buf = rest;
Some(node.0)
Some(node)
} else {
None
};

View File

@ -1186,7 +1186,7 @@ mod tests {
.into_iter()
.map(|item| {
let (key, node) = item.unwrap();
(key.0, node.0)
(key.0, node)
})
.collect();
assert_trie_updates(&account_updates);

View File

@ -48,7 +48,7 @@ where
&mut self,
key: Nibbles,
) -> Result<Option<(Nibbles, BranchNodeCompact)>, DatabaseError> {
Ok(self.0.seek_exact(StoredNibbles(key))?.map(|value| (value.0 .0, value.1 .0)))
Ok(self.0.seek_exact(StoredNibbles(key))?.map(|value| (value.0 .0, value.1)))
}
/// Seeks a key in the account trie that matches or is greater than the provided key.
@ -56,12 +56,12 @@ where
&mut self,
key: Nibbles,
) -> Result<Option<(Nibbles, BranchNodeCompact)>, DatabaseError> {
Ok(self.0.seek(StoredNibbles(key))?.map(|value| (value.0 .0, value.1 .0)))
Ok(self.0.seek(StoredNibbles(key))?.map(|value| (value.0 .0, value.1)))
}
/// Move the cursor to the next entry and return it.
fn next(&mut self) -> Result<Option<(Nibbles, BranchNodeCompact)>, DatabaseError> {
Ok(self.0.next()?.map(|value| (value.0 .0, value.1 .0)))
Ok(self.0.next()?.map(|value| (value.0 .0, value.1)))
}
/// Retrieves the current key in the cursor.
@ -127,7 +127,7 @@ where
#[cfg(test)]
mod tests {
use super::*;
use crate::{StorageTrieEntry, StoredBranchNode};
use crate::StorageTrieEntry;
use reth_db_api::{cursor::DbCursorRW, transaction::DbTxMut};
use reth_primitives::hex_literal::hex;
use reth_provider::test_utils::create_test_provider_factory;
@ -149,13 +149,13 @@ mod tests {
cursor
.upsert(
key.into(),
StoredBranchNode(BranchNodeCompact::new(
BranchNodeCompact::new(
0b0000_0010_0000_0001,
0b0000_0010_0000_0001,
0,
Vec::default(),
None,
)),
),
)
.unwrap();
}

View File

@ -1,4 +1,4 @@
use crate::{nodes::CHILD_INDEX_RANGE, BranchNodeCompact, Nibbles, StoredSubNode};
use crate::{BranchNodeCompact, Nibbles, StoredSubNode, CHILD_INDEX_RANGE};
use reth_primitives::B256;
/// Cursor for iterating over a subtrie.

View File

@ -1,6 +1,6 @@
use crate::{
walker::TrieWalker, BranchNodeCompact, HashBuilder, Nibbles, StorageTrieEntry,
StoredBranchNode, StoredNibbles, StoredNibblesSubKey,
walker::TrieWalker, BranchNodeCompact, HashBuilder, Nibbles, StorageTrieEntry, StoredNibbles,
StoredNibblesSubKey,
};
use reth_db::tables;
use reth_db_api::{
@ -119,7 +119,7 @@ impl TrieUpdates {
Some(node) => {
if !nibbles.0.is_empty() {
num_entries += 1;
account_trie_cursor.upsert(nibbles, StoredBranchNode(node))?;
account_trie_cursor.upsert(nibbles, node)?;
}
}
None => {

View File

@ -242,7 +242,7 @@ mod tests {
use crate::{
prefix_set::PrefixSetMut,
trie_cursor::{DatabaseAccountTrieCursor, DatabaseStorageTrieCursor},
StorageTrieEntry, StoredBranchNode,
StorageTrieEntry,
};
use reth_db::tables;
use reth_db_api::{cursor::DbCursorRW, transaction::DbTxMut};
@ -276,7 +276,7 @@ mod tests {
let mut account_cursor = tx.tx_ref().cursor_write::<tables::AccountsTrie>().unwrap();
for (k, v) in &inputs {
account_cursor.upsert(k.clone().into(), StoredBranchNode(v.clone())).unwrap();
account_cursor.upsert(k.clone().into(), v.clone()).unwrap();
}
let account_trie = DatabaseAccountTrieCursor::new(account_cursor);
test_cursor(account_trie, &expected);