mirror of
https://github.com/hl-archive-node/nanoreth.git
synced 2025-12-06 10:59:55 +00:00
chore: move primitives/trie to reth-trie-types (#8717)
This commit is contained in:
@ -3,10 +3,7 @@ use alloy_rlp::{BufMut, Encodable};
|
||||
use itertools::Itertools;
|
||||
use reth_db_api::database::Database;
|
||||
use reth_execution_errors::StorageRootError;
|
||||
use reth_primitives::{
|
||||
trie::{HashBuilder, Nibbles, TrieAccount},
|
||||
B256,
|
||||
};
|
||||
use reth_primitives::{proofs::IntoTrieAccount, B256};
|
||||
use reth_provider::{providers::ConsistentDbView, DatabaseProviderFactory, ProviderError};
|
||||
use reth_tasks::pool::BlockingTaskPool;
|
||||
use reth_trie::{
|
||||
@ -15,7 +12,7 @@ use reth_trie::{
|
||||
trie_cursor::TrieCursorFactory,
|
||||
updates::TrieUpdates,
|
||||
walker::TrieWalker,
|
||||
HashedPostState, StorageRoot,
|
||||
HashBuilder, HashedPostState, Nibbles, StorageRoot,
|
||||
};
|
||||
use std::{collections::HashMap, sync::Arc};
|
||||
use thiserror::Error;
|
||||
@ -173,7 +170,7 @@ where
|
||||
}
|
||||
|
||||
account_rlp.clear();
|
||||
let account = TrieAccount::from((account, storage_root));
|
||||
let account = IntoTrieAccount::to_trie_account((account, storage_root));
|
||||
account.encode(&mut account_rlp as &mut dyn BufMut);
|
||||
hash_builder.add_leaf(Nibbles::unpack(hashed_address), &account_rlp);
|
||||
}
|
||||
|
||||
@ -3,10 +3,7 @@ use alloy_rlp::{BufMut, Encodable};
|
||||
use rayon::prelude::*;
|
||||
use reth_db_api::database::Database;
|
||||
use reth_execution_errors::StorageRootError;
|
||||
use reth_primitives::{
|
||||
trie::{HashBuilder, Nibbles, TrieAccount},
|
||||
B256,
|
||||
};
|
||||
use reth_primitives::{proofs::IntoTrieAccount, B256};
|
||||
use reth_provider::{providers::ConsistentDbView, DatabaseProviderFactory, ProviderError};
|
||||
use reth_trie::{
|
||||
hashed_cursor::{HashedCursorFactory, HashedPostStateCursorFactory},
|
||||
@ -14,7 +11,7 @@ use reth_trie::{
|
||||
trie_cursor::TrieCursorFactory,
|
||||
updates::TrieUpdates,
|
||||
walker::TrieWalker,
|
||||
HashedPostState, StorageRoot,
|
||||
HashBuilder, HashedPostState, Nibbles, StorageRoot,
|
||||
};
|
||||
use std::collections::HashMap;
|
||||
use thiserror::Error;
|
||||
@ -155,7 +152,7 @@ where
|
||||
}
|
||||
|
||||
account_rlp.clear();
|
||||
let account = TrieAccount::from((account, storage_root));
|
||||
let account = IntoTrieAccount::to_trie_account((account, storage_root));
|
||||
account.encode(&mut account_rlp as &mut dyn BufMut);
|
||||
hash_builder.add_leaf(Nibbles::unpack(hashed_address), &account_rlp);
|
||||
}
|
||||
|
||||
@ -17,6 +17,7 @@ reth-primitives.workspace = true
|
||||
reth-execution-errors.workspace = true
|
||||
reth-db.workspace = true
|
||||
reth-db-api.workspace = true
|
||||
reth-trie-types.workspace = true
|
||||
|
||||
revm.workspace = true
|
||||
|
||||
|
||||
@ -7,8 +7,7 @@ use proptest::{
|
||||
strategy::ValueTree,
|
||||
test_runner::{basic_result_cache, TestRunner},
|
||||
};
|
||||
use reth_primitives::trie::Nibbles;
|
||||
use reth_trie::prefix_set::PrefixSetMut;
|
||||
use reth_trie::{prefix_set::PrefixSetMut, Nibbles};
|
||||
use std::collections::BTreeSet;
|
||||
|
||||
/// Abstractions used for benching
|
||||
|
||||
@ -50,6 +50,9 @@ pub use progress::{IntermediateStateRootState, StateRootProgress};
|
||||
/// Trie calculation stats.
|
||||
pub mod stats;
|
||||
|
||||
// re-export for convenience
|
||||
pub use reth_trie_types::*;
|
||||
|
||||
/// Trie calculation metrics.
|
||||
#[cfg(feature = "metrics")]
|
||||
pub mod metrics;
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
use crate::{hashed_cursor::HashedCursor, trie_cursor::TrieCursor, walker::TrieWalker};
|
||||
use crate::{hashed_cursor::HashedCursor, trie_cursor::TrieCursor, walker::TrieWalker, Nibbles};
|
||||
use reth_db::DatabaseError;
|
||||
use reth_primitives::{trie::Nibbles, B256};
|
||||
use reth_primitives::B256;
|
||||
|
||||
/// Represents a branch node in the trie.
|
||||
#[derive(Debug)]
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
use super::{PrefixSetMut, TriePrefixSets};
|
||||
use crate::Nibbles;
|
||||
use derive_more::Deref;
|
||||
use reth_db::tables;
|
||||
use reth_db_api::{
|
||||
@ -7,12 +8,11 @@ use reth_db_api::{
|
||||
transaction::DbTx,
|
||||
DatabaseError,
|
||||
};
|
||||
use reth_primitives::{keccak256, trie::Nibbles, BlockNumber, StorageEntry, B256};
|
||||
use reth_primitives::{keccak256, BlockNumber, StorageEntry, B256};
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
ops::RangeInclusive,
|
||||
};
|
||||
|
||||
/// A wrapper around a database transaction that loads prefix sets within a given block range.
|
||||
#[derive(Deref, Debug)]
|
||||
pub struct PrefixSetLoader<'a, TX>(&'a TX);
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
use reth_primitives::{trie::Nibbles, B256};
|
||||
use crate::Nibbles;
|
||||
use reth_primitives::B256;
|
||||
use std::{
|
||||
collections::{HashMap, HashSet},
|
||||
sync::Arc,
|
||||
@ -37,8 +38,7 @@ pub struct TriePrefixSets {
|
||||
/// # Examples
|
||||
///
|
||||
/// ```
|
||||
/// use reth_primitives::trie::Nibbles;
|
||||
/// use reth_trie::prefix_set::PrefixSetMut;
|
||||
/// use reth_trie::{prefix_set::PrefixSetMut, Nibbles};
|
||||
///
|
||||
/// let mut prefix_set = PrefixSetMut::default();
|
||||
/// prefix_set.insert(Nibbles::from_nibbles_unchecked(&[0xa, 0xb]));
|
||||
|
||||
@ -1,5 +1,5 @@
|
||||
use crate::{trie_cursor::CursorSubNode, updates::TrieUpdates};
|
||||
use reth_primitives::{stage::MerkleCheckpoint, trie::hash_builder::HashBuilder, B256};
|
||||
use crate::{hash_builder::HashBuilder, trie_cursor::CursorSubNode, updates::TrieUpdates};
|
||||
use reth_primitives::{stage::MerkleCheckpoint, B256};
|
||||
|
||||
/// The progress of the state root computation.
|
||||
#[derive(Debug)]
|
||||
|
||||
@ -4,6 +4,7 @@ use crate::{
|
||||
prefix_set::PrefixSetMut,
|
||||
trie_cursor::{DatabaseAccountTrieCursor, DatabaseStorageTrieCursor},
|
||||
walker::TrieWalker,
|
||||
HashBuilder, Nibbles,
|
||||
};
|
||||
use alloy_rlp::{BufMut, Encodable};
|
||||
use reth_db::tables;
|
||||
@ -12,10 +13,10 @@ use reth_execution_errors::{StateRootError, StorageRootError};
|
||||
use reth_primitives::{
|
||||
constants::EMPTY_ROOT_HASH,
|
||||
keccak256,
|
||||
trie::{proof::ProofRetainer, AccountProof, HashBuilder, Nibbles, StorageProof, TrieAccount},
|
||||
proofs::{AccountProof, IntoTrieAccount, StorageProof},
|
||||
Address, B256,
|
||||
};
|
||||
|
||||
use reth_trie_types::proof::ProofRetainer;
|
||||
/// A struct for generating merkle proofs.
|
||||
///
|
||||
/// Proof generator adds the target address and slots to the prefix set, enables the proof retainer
|
||||
@ -82,7 +83,7 @@ where
|
||||
};
|
||||
|
||||
account_rlp.clear();
|
||||
let account = TrieAccount::from((account, storage_root));
|
||||
let account = IntoTrieAccount::to_trie_account((account, storage_root));
|
||||
account.encode(&mut account_rlp as &mut dyn BufMut);
|
||||
|
||||
hash_builder.add_leaf(Nibbles::unpack(hashed_address), &account_rlp);
|
||||
|
||||
@ -2,7 +2,7 @@ use crate::{
|
||||
hashed_cursor::HashedPostStateCursorFactory,
|
||||
prefix_set::{PrefixSetMut, TriePrefixSets},
|
||||
updates::TrieUpdates,
|
||||
StateRoot,
|
||||
Nibbles, StateRoot,
|
||||
};
|
||||
use rayon::prelude::{IntoParallelIterator, ParallelIterator};
|
||||
use reth_db::{tables, DatabaseError};
|
||||
@ -13,8 +13,7 @@ use reth_db_api::{
|
||||
};
|
||||
use reth_execution_errors::StateRootError;
|
||||
use reth_primitives::{
|
||||
keccak256, revm::compat::into_reth_acc, trie::Nibbles, Account, Address, BlockNumber, B256,
|
||||
U256,
|
||||
keccak256, revm::compat::into_reth_acc, Account, Address, BlockNumber, B256, U256,
|
||||
};
|
||||
use revm::db::BundleAccount;
|
||||
use std::{
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
use alloy_rlp::encode_fixed_size;
|
||||
use reth_primitives::{
|
||||
proofs::triehash::KeccakHasher, trie::TrieAccount, Account, Address, B256, U256,
|
||||
proofs::{triehash::KeccakHasher, IntoTrieAccount},
|
||||
Account, Address, B256, U256,
|
||||
};
|
||||
|
||||
/// Re-export of [triehash].
|
||||
@ -14,7 +15,7 @@ where
|
||||
{
|
||||
let encoded_accounts = accounts.into_iter().map(|(address, (account, storage))| {
|
||||
let storage_root = storage_root(storage);
|
||||
let account = TrieAccount::from((account, storage_root));
|
||||
let account = IntoTrieAccount::to_trie_account((account, storage_root));
|
||||
(address, alloy_rlp::encode(account))
|
||||
});
|
||||
triehash::sec_trie_root::<KeccakHasher, _, _, _>(encoded_accounts)
|
||||
@ -35,7 +36,7 @@ where
|
||||
{
|
||||
let encoded_accounts = accounts.into_iter().map(|(address, (account, storage))| {
|
||||
let storage_root = storage_root_prehashed(storage);
|
||||
let account = TrieAccount::from((account, storage_root));
|
||||
let account = IntoTrieAccount::to_trie_account((account, storage_root));
|
||||
(address, alloy_rlp::encode(account))
|
||||
});
|
||||
|
||||
|
||||
@ -7,15 +7,13 @@ use crate::{
|
||||
trie_cursor::TrieCursorFactory,
|
||||
updates::{TrieKey, TrieOp, TrieUpdates},
|
||||
walker::TrieWalker,
|
||||
HashBuilder, Nibbles,
|
||||
};
|
||||
use alloy_rlp::{BufMut, Encodable};
|
||||
use reth_db_api::transaction::DbTx;
|
||||
use reth_execution_errors::{StateRootError, StorageRootError};
|
||||
use reth_primitives::{
|
||||
constants::EMPTY_ROOT_HASH,
|
||||
keccak256,
|
||||
trie::{HashBuilder, Nibbles, TrieAccount},
|
||||
Address, BlockNumber, B256,
|
||||
constants::EMPTY_ROOT_HASH, keccak256, proofs::IntoTrieAccount, Address, BlockNumber, B256,
|
||||
};
|
||||
use std::ops::RangeInclusive;
|
||||
use tracing::{debug, trace};
|
||||
@ -284,7 +282,7 @@ where
|
||||
};
|
||||
|
||||
account_rlp.clear();
|
||||
let account = TrieAccount::from((account, storage_root));
|
||||
let account = IntoTrieAccount::to_trie_account((account, storage_root));
|
||||
account.encode(&mut account_rlp as &mut dyn BufMut);
|
||||
hash_builder.add_leaf(Nibbles::unpack(hashed_address), &account_rlp);
|
||||
|
||||
@ -552,6 +550,7 @@ mod tests {
|
||||
use crate::{
|
||||
prefix_set::PrefixSetMut,
|
||||
test_utils::{state_root, state_root_prehashed, storage_root, storage_root_prehashed},
|
||||
BranchNodeCompact, TrieMask,
|
||||
};
|
||||
use proptest::{prelude::ProptestConfig, proptest};
|
||||
use reth_db::{tables, test_utils::TempDatabase, DatabaseEnv};
|
||||
@ -560,10 +559,7 @@ mod tests {
|
||||
transaction::DbTxMut,
|
||||
};
|
||||
use reth_primitives::{
|
||||
hex_literal::hex,
|
||||
proofs::triehash::KeccakHasher,
|
||||
trie::{BranchNodeCompact, TrieMask},
|
||||
Account, StorageEntry, U256,
|
||||
hex_literal::hex, proofs::triehash::KeccakHasher, Account, StorageEntry, U256,
|
||||
};
|
||||
use reth_provider::{test_utils::create_test_provider_factory, DatabaseProviderRW};
|
||||
use std::{
|
||||
@ -832,7 +828,8 @@ mod tests {
|
||||
}
|
||||
|
||||
fn encode_account(account: Account, storage_root: Option<B256>) -> Vec<u8> {
|
||||
let account = TrieAccount::from((account, storage_root.unwrap_or(EMPTY_ROOT_HASH)));
|
||||
let account =
|
||||
IntoTrieAccount::to_trie_account((account, storage_root.unwrap_or(EMPTY_ROOT_HASH)));
|
||||
let mut account_rlp = Vec::with_capacity(account.length());
|
||||
account.encode(&mut account_rlp);
|
||||
account_rlp
|
||||
|
||||
@ -1,14 +1,11 @@
|
||||
use super::{TrieCursor, TrieCursorFactory};
|
||||
use crate::updates::TrieKey;
|
||||
use crate::{updates::TrieKey, BranchNodeCompact, Nibbles, StoredNibbles, StoredNibblesSubKey};
|
||||
use reth_db::{tables, DatabaseError};
|
||||
use reth_db_api::{
|
||||
cursor::{DbCursorRO, DbDupCursorRO},
|
||||
transaction::DbTx,
|
||||
};
|
||||
use reth_primitives::{
|
||||
trie::{BranchNodeCompact, Nibbles, StoredNibbles, StoredNibblesSubKey},
|
||||
B256,
|
||||
};
|
||||
use reth_primitives::B256;
|
||||
|
||||
/// Implementation of the trie cursor factory for a database transaction.
|
||||
impl<'a, TX: DbTx> TrieCursorFactory for &'a TX {
|
||||
@ -116,11 +113,9 @@ where
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::{StorageTrieEntry, StoredBranchNode};
|
||||
use reth_db_api::{cursor::DbCursorRW, transaction::DbTxMut};
|
||||
use reth_primitives::{
|
||||
hex_literal::hex,
|
||||
trie::{StorageTrieEntry, StoredBranchNode},
|
||||
};
|
||||
use reth_primitives::hex_literal::hex;
|
||||
use reth_provider::test_utils::create_test_provider_factory;
|
||||
|
||||
#[test]
|
||||
|
||||
@ -1,10 +1,6 @@
|
||||
use crate::updates::TrieKey;
|
||||
use crate::{updates::TrieKey, BranchNodeCompact, Nibbles};
|
||||
use reth_db::DatabaseError;
|
||||
use reth_primitives::{
|
||||
trie::{BranchNodeCompact, Nibbles},
|
||||
B256,
|
||||
};
|
||||
|
||||
use reth_primitives::B256;
|
||||
mod database_cursors;
|
||||
mod subnode;
|
||||
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
use super::{TrieCursor, TrieCursorFactory};
|
||||
use crate::updates::TrieKey;
|
||||
use crate::{updates::TrieKey, BranchNodeCompact, Nibbles};
|
||||
use reth_db::DatabaseError;
|
||||
use reth_primitives::trie::{BranchNodeCompact, Nibbles};
|
||||
|
||||
/// Noop trie cursor factory.
|
||||
#[derive(Default, Debug)]
|
||||
|
||||
@ -1,7 +1,5 @@
|
||||
use reth_primitives::{
|
||||
trie::{nodes::CHILD_INDEX_RANGE, BranchNodeCompact, Nibbles, StoredSubNode},
|
||||
B256,
|
||||
};
|
||||
use crate::{nodes::CHILD_INDEX_RANGE, BranchNodeCompact, Nibbles, StoredSubNode};
|
||||
use reth_primitives::B256;
|
||||
|
||||
/// Cursor for iterating over a subtrie.
|
||||
#[derive(Clone)]
|
||||
|
||||
@ -1,17 +1,14 @@
|
||||
use crate::walker::TrieWalker;
|
||||
use crate::{
|
||||
walker::TrieWalker, BranchNodeCompact, HashBuilder, Nibbles, StorageTrieEntry,
|
||||
StoredBranchNode, StoredNibbles, StoredNibblesSubKey,
|
||||
};
|
||||
use derive_more::Deref;
|
||||
use reth_db::tables;
|
||||
use reth_db_api::{
|
||||
cursor::{DbCursorRO, DbCursorRW, DbDupCursorRO, DbDupCursorRW},
|
||||
transaction::{DbTx, DbTxMut},
|
||||
};
|
||||
use reth_primitives::{
|
||||
trie::{
|
||||
BranchNodeCompact, HashBuilder, Nibbles, StorageTrieEntry, StoredBranchNode, StoredNibbles,
|
||||
StoredNibblesSubKey,
|
||||
},
|
||||
B256,
|
||||
};
|
||||
use reth_primitives::B256;
|
||||
use std::collections::{hash_map::IntoIter, HashMap, HashSet};
|
||||
|
||||
/// The key of a trie node.
|
||||
|
||||
@ -2,12 +2,10 @@ use crate::{
|
||||
prefix_set::PrefixSet,
|
||||
trie_cursor::{CursorSubNode, TrieCursor},
|
||||
updates::TrieUpdates,
|
||||
BranchNodeCompact, Nibbles,
|
||||
};
|
||||
use reth_db::DatabaseError;
|
||||
use reth_primitives::{
|
||||
trie::{BranchNodeCompact, Nibbles},
|
||||
B256,
|
||||
};
|
||||
use reth_primitives::B256;
|
||||
|
||||
/// `TrieWalker` is a structure that enables traversal of a Merkle trie.
|
||||
/// It allows moving through the trie in a depth-first manner, skipping certain branches
|
||||
@ -249,10 +247,10 @@ mod tests {
|
||||
use crate::{
|
||||
prefix_set::PrefixSetMut,
|
||||
trie_cursor::{DatabaseAccountTrieCursor, DatabaseStorageTrieCursor},
|
||||
StorageTrieEntry, StoredBranchNode,
|
||||
};
|
||||
use reth_db::tables;
|
||||
use reth_db_api::{cursor::DbCursorRW, transaction::DbTxMut};
|
||||
use reth_primitives::trie::{StorageTrieEntry, StoredBranchNode};
|
||||
use reth_provider::test_utils::create_test_provider_factory;
|
||||
|
||||
#[test]
|
||||
|
||||
33
crates/trie/types/Cargo.toml
Normal file
33
crates/trie/types/Cargo.toml
Normal file
@ -0,0 +1,33 @@
|
||||
[package]
|
||||
name = "reth-trie-types"
|
||||
version.workspace = true
|
||||
edition.workspace = true
|
||||
homepage.workspace = true
|
||||
license.workspace = true
|
||||
repository.workspace = true
|
||||
rust-version.workspace = true
|
||||
description = "Commonly used types for trie usage in reth."
|
||||
|
||||
[lints]
|
||||
workspace = true
|
||||
|
||||
[dependencies]
|
||||
reth-codecs.workspace = true
|
||||
|
||||
alloy-primitives.workspace = true
|
||||
alloy-rlp = { workspace = true, features = ["arrayvec"] }
|
||||
alloy-trie = { workspace = true, features = ["serde"] }
|
||||
bytes.workspace = true
|
||||
derive_more.workspace = true
|
||||
serde.workspace = true
|
||||
|
||||
nybbles = { workspace = true, features = ["serde", "rlp"] }
|
||||
|
||||
[dev-dependencies]
|
||||
arbitrary = { workspace = true, features = ["derive"] }
|
||||
assert_matches.workspace = true
|
||||
proptest.workspace = true
|
||||
proptest-derive.workspace = true
|
||||
serde_json.workspace = true
|
||||
test-fuzz.workspace = true
|
||||
toml.workspace = true
|
||||
22
crates/trie/types/src/account.rs
Normal file
22
crates/trie/types/src/account.rs
Normal file
@ -0,0 +1,22 @@
|
||||
use alloy_primitives::{B256, U256};
|
||||
use alloy_rlp::{RlpDecodable, RlpEncodable};
|
||||
|
||||
/// An Ethereum account as represented in the trie.
|
||||
#[derive(Clone, Copy, Debug, PartialEq, Eq, Default, RlpEncodable, RlpDecodable)]
|
||||
pub struct TrieAccount {
|
||||
/// Account nonce.
|
||||
pub nonce: u64,
|
||||
/// Account balance.
|
||||
pub balance: U256,
|
||||
/// Account's storage root.
|
||||
pub storage_root: B256,
|
||||
/// Hash of the account's bytecode.
|
||||
pub code_hash: B256,
|
||||
}
|
||||
|
||||
impl TrieAccount {
|
||||
/// Get account's storage root.
|
||||
pub const fn storage_root(&self) -> B256 {
|
||||
self.storage_root
|
||||
}
|
||||
}
|
||||
9
crates/trie/types/src/hash_builder/mod.rs
Normal file
9
crates/trie/types/src/hash_builder/mod.rs
Normal file
@ -0,0 +1,9 @@
|
||||
//! MPT hash builder implementation.
|
||||
|
||||
mod state;
|
||||
pub use state::HashBuilderState;
|
||||
|
||||
mod value;
|
||||
pub(crate) use value::StoredHashBuilderValue;
|
||||
|
||||
pub use alloy_trie::hash_builder::*;
|
||||
171
crates/trie/types/src/hash_builder/state.rs
Normal file
171
crates/trie/types/src/hash_builder/state.rs
Normal file
@ -0,0 +1,171 @@
|
||||
use super::StoredHashBuilderValue;
|
||||
use crate::{StoredTrieMask, TrieMask};
|
||||
use alloy_trie::{hash_builder::HashBuilderValue, HashBuilder};
|
||||
use bytes::Buf;
|
||||
use nybbles::Nibbles;
|
||||
use reth_codecs::{derive_arbitrary, Compact};
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// The hash builder state for storing in the database.
|
||||
/// Check the `reth-trie` crate for more info on hash builder.
|
||||
#[derive_arbitrary(compact)]
|
||||
#[derive(Debug, Clone, PartialEq, Default, Serialize, Deserialize)]
|
||||
pub struct HashBuilderState {
|
||||
/// The current key.
|
||||
pub key: Vec<u8>,
|
||||
/// The builder stack.
|
||||
pub stack: Vec<Vec<u8>>,
|
||||
/// The current node value.
|
||||
pub value: HashBuilderValue,
|
||||
|
||||
/// Group masks.
|
||||
pub groups: Vec<TrieMask>,
|
||||
/// Tree masks.
|
||||
pub tree_masks: Vec<TrieMask>,
|
||||
/// Hash masks.
|
||||
pub hash_masks: Vec<TrieMask>,
|
||||
|
||||
/// Flag indicating if the current node is stored in the database.
|
||||
pub stored_in_database: bool,
|
||||
}
|
||||
|
||||
impl From<HashBuilderState> for HashBuilder {
|
||||
fn from(state: HashBuilderState) -> Self {
|
||||
Self {
|
||||
key: Nibbles::from_nibbles_unchecked(state.key),
|
||||
stack: state.stack,
|
||||
value: state.value,
|
||||
groups: state.groups,
|
||||
tree_masks: state.tree_masks,
|
||||
hash_masks: state.hash_masks,
|
||||
stored_in_database: state.stored_in_database,
|
||||
updated_branch_nodes: None,
|
||||
proof_retainer: None,
|
||||
rlp_buf: Vec::with_capacity(32),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl From<HashBuilder> for HashBuilderState {
|
||||
fn from(state: HashBuilder) -> Self {
|
||||
Self {
|
||||
key: state.key.into(),
|
||||
stack: state.stack,
|
||||
value: state.value,
|
||||
groups: state.groups,
|
||||
tree_masks: state.tree_masks,
|
||||
hash_masks: state.hash_masks,
|
||||
stored_in_database: state.stored_in_database,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Compact for HashBuilderState {
|
||||
fn to_compact<B>(self, buf: &mut B) -> usize
|
||||
where
|
||||
B: bytes::BufMut + AsMut<[u8]>,
|
||||
{
|
||||
let mut len = 0;
|
||||
|
||||
len += self.key.to_compact(buf);
|
||||
|
||||
buf.put_u16(self.stack.len() as u16);
|
||||
len += 2;
|
||||
for item in &self.stack {
|
||||
buf.put_u16(item.len() as u16);
|
||||
buf.put_slice(&item[..]);
|
||||
len += 2 + item.len();
|
||||
}
|
||||
|
||||
len += StoredHashBuilderValue(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);
|
||||
}
|
||||
|
||||
buf.put_u16(self.tree_masks.len() as u16);
|
||||
len += 2;
|
||||
for item in &self.tree_masks {
|
||||
len += StoredTrieMask(*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);
|
||||
}
|
||||
|
||||
buf.put_u8(self.stored_in_database as u8);
|
||||
len += 1;
|
||||
len
|
||||
}
|
||||
|
||||
fn from_compact(buf: &[u8], _len: usize) -> (Self, &[u8]) {
|
||||
let (key, mut buf) = Vec::from_compact(buf, 0);
|
||||
|
||||
let stack_len = buf.get_u16() as usize;
|
||||
let mut stack = Vec::with_capacity(stack_len);
|
||||
for _ in 0..stack_len {
|
||||
let item_len = buf.get_u16() as usize;
|
||||
stack.push(Vec::from(&buf[..item_len]));
|
||||
buf.advance(item_len);
|
||||
}
|
||||
|
||||
let (StoredHashBuilderValue(value), mut buf) = StoredHashBuilderValue::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);
|
||||
groups.push(item);
|
||||
buf = rest;
|
||||
}
|
||||
|
||||
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);
|
||||
tree_masks.push(item);
|
||||
buf = rest;
|
||||
}
|
||||
|
||||
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);
|
||||
hash_masks.push(item);
|
||||
buf = rest;
|
||||
}
|
||||
|
||||
let stored_in_database = buf.get_u8() != 0;
|
||||
(Self { key, stack, value, groups, tree_masks, hash_masks, stored_in_database }, buf)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use proptest::prelude::*;
|
||||
|
||||
#[test]
|
||||
fn hash_builder_state_regression() {
|
||||
let mut state = HashBuilderState::default();
|
||||
state.stack.push(vec![]);
|
||||
let mut buf = vec![];
|
||||
let len = state.clone().to_compact(&mut buf);
|
||||
let (decoded, _) = HashBuilderState::from_compact(&buf, len);
|
||||
assert_eq!(state, decoded);
|
||||
}
|
||||
|
||||
proptest! {
|
||||
#[test]
|
||||
fn hash_builder_state_roundtrip(state: HashBuilderState) {
|
||||
let mut buf = vec![];
|
||||
let len = state.clone().to_compact(&mut buf);
|
||||
let (decoded, _) = HashBuilderState::from_compact(&buf, len);
|
||||
assert_eq!(state, decoded);
|
||||
}
|
||||
}
|
||||
}
|
||||
43
crates/trie/types/src/hash_builder/value.rs
Normal file
43
crates/trie/types/src/hash_builder/value.rs
Normal file
@ -0,0 +1,43 @@
|
||||
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"),
|
||||
}
|
||||
}
|
||||
}
|
||||
34
crates/trie/types/src/lib.rs
Normal file
34
crates/trie/types/src/lib.rs
Normal file
@ -0,0 +1,34 @@
|
||||
//! Commonly used types for trie usage.
|
||||
|
||||
#![doc(
|
||||
html_logo_url = "https://raw.githubusercontent.com/paradigmxyz/reth/main/assets/reth-docs.png",
|
||||
html_favicon_url = "https://avatars0.githubusercontent.com/u/97369466?s=256",
|
||||
issue_tracker_base_url = "https://github.com/paradigmxyz/reth/issues/"
|
||||
)]
|
||||
#![cfg_attr(not(test), warn(unused_crate_dependencies))]
|
||||
// TODO: remove when https://github.com/proptest-rs/proptest/pull/427 is merged
|
||||
#![allow(unknown_lints, non_local_definitions)]
|
||||
#![cfg_attr(docsrs, feature(doc_cfg, doc_auto_cfg))]
|
||||
|
||||
/// The implementation of hash builder.
|
||||
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;
|
||||
|
||||
mod subnode;
|
||||
pub use subnode::StoredSubNode;
|
||||
|
||||
pub use alloy_trie::{proof, BranchNodeCompact, HashBuilder, TrieMask, EMPTY_ROOT_HASH};
|
||||
20
crates/trie/types/src/mask.rs
Normal file
20
crates/trie/types/src/mask.rs
Normal file
@ -0,0 +1,20 @@
|
||||
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)
|
||||
}
|
||||
}
|
||||
120
crates/trie/types/src/nibbles.rs
Normal file
120
crates/trie/types/src/nibbles.rs
Normal file
@ -0,0 +1,120 @@
|
||||
use bytes::Buf;
|
||||
use derive_more::Deref;
|
||||
use reth_codecs::Compact;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
pub use nybbles::Nibbles;
|
||||
|
||||
/// The representation of nibbles of the merkle trie stored in the database.
|
||||
#[derive(
|
||||
Clone,
|
||||
Debug,
|
||||
Default,
|
||||
PartialEq,
|
||||
Eq,
|
||||
PartialOrd,
|
||||
Ord,
|
||||
Hash,
|
||||
Serialize,
|
||||
Deserialize,
|
||||
derive_more::Index,
|
||||
)]
|
||||
pub struct StoredNibbles(pub Nibbles);
|
||||
|
||||
impl From<Nibbles> for StoredNibbles {
|
||||
#[inline]
|
||||
fn from(value: Nibbles) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<u8>> for StoredNibbles {
|
||||
#[inline]
|
||||
fn from(value: Vec<u8>) -> Self {
|
||||
Self(Nibbles::from_nibbles_unchecked(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialEq<[u8]> for StoredNibbles {
|
||||
#[inline]
|
||||
fn eq(&self, other: &[u8]) -> bool {
|
||||
self.0.as_slice() == other
|
||||
}
|
||||
}
|
||||
|
||||
impl PartialOrd<[u8]> for StoredNibbles {
|
||||
#[inline]
|
||||
fn partial_cmp(&self, other: &[u8]) -> Option<std::cmp::Ordering> {
|
||||
self.0.as_slice().partial_cmp(other)
|
||||
}
|
||||
}
|
||||
|
||||
impl core::borrow::Borrow<[u8]> for StoredNibbles {
|
||||
#[inline]
|
||||
fn borrow(&self) -> &[u8] {
|
||||
self.0.as_slice()
|
||||
}
|
||||
}
|
||||
|
||||
impl Compact for StoredNibbles {
|
||||
fn to_compact<B>(self, buf: &mut B) -> usize
|
||||
where
|
||||
B: bytes::BufMut + AsMut<[u8]>,
|
||||
{
|
||||
buf.put_slice(self.0.as_slice());
|
||||
self.0.len()
|
||||
}
|
||||
|
||||
fn from_compact(mut buf: &[u8], len: usize) -> (Self, &[u8]) {
|
||||
let nibbles = &buf[..len];
|
||||
buf.advance(len);
|
||||
(Self(Nibbles::from_nibbles_unchecked(nibbles)), buf)
|
||||
}
|
||||
}
|
||||
|
||||
/// The representation of nibbles of the merkle trie stored in the database.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, PartialOrd, Ord, Hash, Deref)]
|
||||
pub struct StoredNibblesSubKey(pub Nibbles);
|
||||
|
||||
impl From<Nibbles> for StoredNibblesSubKey {
|
||||
#[inline]
|
||||
fn from(value: Nibbles) -> Self {
|
||||
Self(value)
|
||||
}
|
||||
}
|
||||
|
||||
impl From<Vec<u8>> for StoredNibblesSubKey {
|
||||
#[inline]
|
||||
fn from(value: Vec<u8>) -> Self {
|
||||
Self(Nibbles::from_nibbles_unchecked(value))
|
||||
}
|
||||
}
|
||||
|
||||
impl From<StoredNibblesSubKey> for Nibbles {
|
||||
#[inline]
|
||||
fn from(value: StoredNibblesSubKey) -> Self {
|
||||
value.0
|
||||
}
|
||||
}
|
||||
|
||||
impl Compact for StoredNibblesSubKey {
|
||||
fn to_compact<B>(self, buf: &mut B) -> usize
|
||||
where
|
||||
B: bytes::BufMut + AsMut<[u8]>,
|
||||
{
|
||||
assert!(self.0.len() <= 64);
|
||||
|
||||
// right-pad with zeros
|
||||
buf.put_slice(&self.0[..]);
|
||||
static ZERO: &[u8; 64] = &[0; 64];
|
||||
buf.put_slice(&ZERO[self.0.len()..]);
|
||||
|
||||
buf.put_u8(self.0.len() as u8);
|
||||
64 + 1
|
||||
}
|
||||
|
||||
fn from_compact(buf: &[u8], _len: usize) -> (Self, &[u8]) {
|
||||
let len = buf[64] as usize;
|
||||
(Self(Nibbles::from_nibbles_unchecked(&buf[..len])), &buf[65..])
|
||||
}
|
||||
}
|
||||
93
crates/trie/types/src/nodes/branch.rs
Normal file
93
crates/trie/types/src/nodes/branch.rs
Normal file
@ -0,0 +1,93 @@
|
||||
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);
|
||||
}
|
||||
}
|
||||
6
crates/trie/types/src/nodes/mod.rs
Normal file
6
crates/trie/types/src/nodes/mod.rs
Normal file
@ -0,0 +1,6 @@
|
||||
//! Various branch nodes produced by the hash builder.
|
||||
|
||||
mod branch;
|
||||
pub use branch::StoredBranchNode;
|
||||
|
||||
pub use alloy_trie::nodes::*;
|
||||
33
crates/trie/types/src/storage.rs
Normal file
33
crates/trie/types/src/storage.rs
Normal file
@ -0,0 +1,33 @@
|
||||
use super::{BranchNodeCompact, StoredBranchNode, StoredNibblesSubKey};
|
||||
use reth_codecs::Compact;
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
/// Account storage trie node.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize, PartialOrd, Ord)]
|
||||
pub struct StorageTrieEntry {
|
||||
/// The nibbles of the intermediate node
|
||||
pub nibbles: StoredNibblesSubKey,
|
||||
/// Encoded node.
|
||||
pub node: BranchNodeCompact,
|
||||
}
|
||||
|
||||
// NOTE: Removing main_codec and manually encode subkey
|
||||
// and compress second part of the value. If we have compression
|
||||
// over whole value (Even SubKey) that would mess up fetching of values with seek_by_key_subkey
|
||||
impl Compact for StorageTrieEntry {
|
||||
fn to_compact<B>(self, buf: &mut B) -> usize
|
||||
where
|
||||
B: bytes::BufMut + AsMut<[u8]>,
|
||||
{
|
||||
let nibbles_len = self.nibbles.to_compact(buf);
|
||||
let node_len = StoredBranchNode(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 };
|
||||
(this, buf)
|
||||
}
|
||||
}
|
||||
95
crates/trie/types/src/subnode.rs
Normal file
95
crates/trie/types/src/subnode.rs
Normal file
@ -0,0 +1,95 @@
|
||||
use super::{BranchNodeCompact, StoredBranchNode};
|
||||
use bytes::Buf;
|
||||
use reth_codecs::Compact;
|
||||
|
||||
/// Walker sub node for storing intermediate state root calculation state in the database.
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Default)]
|
||||
pub struct StoredSubNode {
|
||||
/// The key of the current node.
|
||||
pub key: Vec<u8>,
|
||||
/// The index of the next child to visit.
|
||||
pub nibble: Option<u8>,
|
||||
/// The node itself.
|
||||
pub node: Option<BranchNodeCompact>,
|
||||
}
|
||||
|
||||
impl Compact for StoredSubNode {
|
||||
fn to_compact<B>(self, buf: &mut B) -> usize
|
||||
where
|
||||
B: bytes::BufMut + AsMut<[u8]>,
|
||||
{
|
||||
let mut len = 0;
|
||||
|
||||
buf.put_u16(self.key.len() as u16);
|
||||
buf.put_slice(&self.key[..]);
|
||||
len += 2 + self.key.len();
|
||||
|
||||
if let Some(nibble) = self.nibble {
|
||||
buf.put_u8(1);
|
||||
buf.put_u8(nibble);
|
||||
len += 2;
|
||||
} else {
|
||||
buf.put_u8(0);
|
||||
len += 1;
|
||||
}
|
||||
|
||||
if let Some(node) = self.node {
|
||||
buf.put_u8(1);
|
||||
len += 1;
|
||||
len += StoredBranchNode(node).to_compact(buf);
|
||||
} else {
|
||||
len += 1;
|
||||
buf.put_u8(0);
|
||||
}
|
||||
|
||||
len
|
||||
}
|
||||
|
||||
fn from_compact(mut buf: &[u8], _len: usize) -> (Self, &[u8]) {
|
||||
let key_len = buf.get_u16() as usize;
|
||||
let key = Vec::from(&buf[..key_len]);
|
||||
buf.advance(key_len);
|
||||
|
||||
let nibbles_exists = buf.get_u8() != 0;
|
||||
let nibble = if nibbles_exists { Some(buf.get_u8()) } else { None };
|
||||
|
||||
let node_exists = buf.get_u8() != 0;
|
||||
let node = if node_exists {
|
||||
let (node, rest) = StoredBranchNode::from_compact(buf, 0);
|
||||
buf = rest;
|
||||
Some(node.0)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
(Self { key, nibble, node }, buf)
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
use crate::TrieMask;
|
||||
use alloy_primitives::B256;
|
||||
|
||||
#[test]
|
||||
fn subnode_roundtrip() {
|
||||
let subnode = StoredSubNode {
|
||||
key: vec![],
|
||||
nibble: None,
|
||||
node: Some(BranchNodeCompact {
|
||||
state_mask: TrieMask::new(1),
|
||||
tree_mask: TrieMask::new(0),
|
||||
hash_mask: TrieMask::new(1),
|
||||
hashes: vec![B256::ZERO],
|
||||
root_hash: None,
|
||||
}),
|
||||
};
|
||||
|
||||
let mut encoded = vec![];
|
||||
subnode.clone().to_compact(&mut encoded);
|
||||
let (decoded, _) = StoredSubNode::from_compact(&encoded[..], 0);
|
||||
|
||||
assert_eq!(subnode, decoded);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user