Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Trie debug tooling #6

Merged
merged 20 commits into from
Feb 5, 2024
Merged
Show file tree
Hide file tree
Changes from 16 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 7 additions & 3 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ exclude = [

[dependencies]
bytes = "1.4.0"
enum-as-inner = "0.5.1"
enum-as-inner = "0.6.0"
ethereum-types = "0.14.1"
hex = "0.4.3"
keccak-hash = "0.10.0"
Expand All @@ -30,13 +30,17 @@ rlp = "0.5.2"
serde = { version = "1.0.160", features = ["derive", "rc"] }

[dev-dependencies]
eth_trie = "0.1.0"
pretty_env_logger = "0.4.0"
eth_trie = "0.4.0"
pretty_env_logger = "0.5.0"
rand = "0.8.5"
rlp-derive = "0.1.0"
serde = { version = "1.0.160", features = ["derive"] }
serde_json = "1.0.96"

[features]
default = ["trie_debug"]
trie_debug = []

[lib]
doc-scrape-examples = true

Expand Down
120 changes: 120 additions & 0 deletions src/debug_tools/common.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
use std::fmt::{self, Display};

use crate::{
nibbles::{Nibble, Nibbles},
partial_trie::{Node, PartialTrie},
utils::TrieNodeType,
};

#[derive(Clone, Debug, Eq, Hash, PartialEq)]
pub(super) enum PathSegment {
Empty,
Hash,
Branch(Nibble),
Extension(Nibbles),
Leaf(Nibbles),
}

impl Display for PathSegment {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
PathSegment::Empty => write!(f, "Empty"),
PathSegment::Hash => write!(f, "Hash"),
PathSegment::Branch(nib) => write!(f, "Branch({})", nib),
PathSegment::Extension(nibs) => write!(f, "Extension({})", nibs),
PathSegment::Leaf(nibs) => write!(f, "Leaf({})", nibs),
Nashtare marked this conversation as resolved.
Show resolved Hide resolved
}
}
}

impl PathSegment {
pub(super) fn node_type(&self) -> TrieNodeType {
match self {
PathSegment::Empty => TrieNodeType::Empty,
PathSegment::Hash => TrieNodeType::Hash,
PathSegment::Branch(_) => TrieNodeType::Branch,
PathSegment::Extension(_) => TrieNodeType::Extension,
PathSegment::Leaf(_) => TrieNodeType::Leaf,
}
}

pub(super) fn get_key_piece_from_seg_if_present(&self) -> Option<Nibbles> {
match self {
PathSegment::Empty | PathSegment::Hash => None,
PathSegment::Branch(nib) => Some(Nibbles::from_nibble(*nib)),
PathSegment::Extension(nibs) => Some(*nibs),
PathSegment::Leaf(nibs) => Some(*nibs),
BGluth marked this conversation as resolved.
Show resolved Hide resolved
}
}
}

pub(super) fn get_segment_from_node_and_key_piece<T: PartialTrie>(
n: &Node<T>,
k_piece: &Nibbles,
) -> PathSegment {
match TrieNodeType::from(n) {
TrieNodeType::Empty => PathSegment::Empty,
TrieNodeType::Hash => PathSegment::Hash,
TrieNodeType::Branch => PathSegment::Branch(k_piece.get_nibble(0)),
TrieNodeType::Extension => PathSegment::Extension(*k_piece),
TrieNodeType::Leaf => PathSegment::Leaf(*k_piece),
}
}

pub(super) fn get_key_piece_from_node<T: PartialTrie>(n: &Node<T>, curr_key: &Nibbles) -> Nibbles {
match n {
Node::Empty | Node::Hash(_) => Nibbles::default(),
Node::Branch { .. } => curr_key.get_next_nibbles(1),
Node::Extension { nibbles, child: _ } => *nibbles,
Node::Leaf { nibbles, value: _ } => *nibbles,
BGluth marked this conversation as resolved.
Show resolved Hide resolved
}
}

// It might seem a bit weird to say a branch has no key piece, but this function
// is used to detect two nodes of the same type that have different keys.
pub(super) fn get_key_piece_from_node_no_branch_key<T: PartialTrie>(n: &Node<T>) -> Nibbles {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The naming is a bit hard to decrypt, without reading the comment (which won't show up in rustdoc). Though I don't have a better suggestion in mind.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'll come up with something better...

Copy link
Collaborator Author

@BGluth BGluth Feb 2, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Potentially a bit better?

/// Get the key piece from the given node if applicable.
///
/// Note that there is no specific [`Nibble`] associated with a branch like
/// there is with [Extension][`Node::Extension`] and [Leaf][`Node::Leaf`] nodes,
/// and the only way to get the nibble "associated" with branches is to look at
/// the next Nibble in the current key as we traverse down it.
pub(super) fn get_key_piece_from_node_pulling_from_key_for_branches<T: PartialTrie>(
    n: &Node<T>,
    curr_key: &Nibbles,
) -> Nibbles {
    ...
}

/// Get the key piece from the given node if applicable. Note that
/// [branch][`Node::Branch`]s have no [`Nibble`] directly associated with them.
pub(super) fn get_key_piece_from_node<T: PartialTrie>(n: &Node<T>) -> Nibbles {
    ...
}

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So yes, it's easier to understand, but now I think we've hit another issue 😆 I think we usually should try to not have function names with more than 5/6 words max. But let's go with it, we can always do a pass on renaming long functions into clearer names later on.

match n {
Node::Empty | Node::Hash(_) | Node::Branch { .. } => Nibbles::default(),
Node::Extension { nibbles, child: _ } => *nibbles,
Node::Leaf { nibbles, value: _ } => *nibbles,
BGluth marked this conversation as resolved.
Show resolved Hide resolved
}
}

#[derive(Clone, Debug, Default, Eq, Hash, PartialEq)]
pub struct NodePath(pub(super) Vec<PathSegment>);

impl NodePath {
pub(super) fn dup_and_append(&self, seg: PathSegment) -> Self {
let mut duped_vec = self.0.clone();
duped_vec.push(seg);

Self(duped_vec)
}

pub(super) fn append(&mut self, seg: PathSegment) {
self.0.push(seg);
}

fn write_elem(f: &mut fmt::Formatter<'_>, seg: &PathSegment) -> fmt::Result {
write!(f, "{}", seg)
}
}

impl Display for NodePath {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
let num_elems = self.0.len();

// For everything but the last elem.
for seg in self.0.iter().take(num_elems.saturating_sub(1)) {
Self::write_elem(f, seg)?;
write!(f, " --> ")?;
}

// Avoid the extra `-->` for the last elem.
if let Some(seg) = self.0.last() {
Self::write_elem(f, seg)?;
}

Ok(())
}
}
Loading