Skip to content

Commit 1360e78

Browse files
authored
Merge 7d44ad2 into 656d028
2 parents 656d028 + 7d44ad2 commit 1360e78

File tree

5 files changed

+213
-65
lines changed

5 files changed

+213
-65
lines changed

crates/common/trie/error.rs

Lines changed: 35 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,18 +1,51 @@
1+
use ethereum_types::H256;
12
use ethrex_rlp::error::RLPDecodeError;
23
use thiserror::Error;
34

5+
use crate::Nibbles;
6+
47
#[derive(Debug, Error)]
58
pub enum TrieError {
69
#[error(transparent)]
710
RLPDecode(#[from] RLPDecodeError),
811
#[error("Verification Error: {0}")]
912
Verify(String),
10-
#[error("Inconsistent internal tree structure")]
11-
InconsistentTree,
13+
#[error("Inconsistent internal tree structure: {0}")]
14+
InconsistentTree(#[from] InconsistentTreeError),
1215
#[error("Lock Error: Panicked when trying to acquire a lock")]
1316
LockError,
1417
#[error("Database error: {0}")]
1518
DbError(anyhow::Error),
1619
#[error("Invalid trie input")]
1720
InvalidInput,
1821
}
22+
23+
#[derive(Debug, Error)]
24+
pub enum InconsistentTreeError {
25+
#[error("Failed to insert node as child of Extention node: {0}")]
26+
ExtensionNodeInsertionError(Box<ExtensionNodeErrorData>),
27+
#[error("Node with hash {0:#x} not found in Branch Node with hash {1:#x} using path {2:?}")]
28+
NodeNotFoundOnBranchNode(H256, H256, Nibbles),
29+
#[error("{0}")]
30+
NodeNotFoundOnExtensionNode(Box<ExtensionNodeErrorData>),
31+
#[error("Root node with hash {0:#x} not found")]
32+
RootNotFound(H256),
33+
}
34+
35+
#[derive(Debug)]
36+
pub struct ExtensionNodeErrorData {
37+
pub node_hash: H256,
38+
pub extension_node_hash: H256,
39+
pub extension_node_prefix: Nibbles,
40+
pub node_path: Nibbles,
41+
}
42+
43+
impl std::fmt::Display for ExtensionNodeErrorData {
44+
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
45+
write!(
46+
f,
47+
"Node with hash {:#x} not found as child of Extension Node with hash {:#x} and prefix {:?} using path {:?}",
48+
self.node_hash, self.extension_node_hash, self.extension_node_hash, self.node_path
49+
)
50+
}
51+
}

crates/common/trie/node/branch.rs

Lines changed: 55 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,9 @@
11
use ethrex_rlp::structs::Encoder;
22

3-
use crate::{TrieDB, ValueRLP, error::TrieError, nibbles::Nibbles, node_hash::NodeHash};
3+
use crate::{
4+
InconsistentTreeError, TrieDB, ValueRLP, error::TrieError, nibbles::Nibbles,
5+
node_hash::NodeHash,
6+
};
47

58
use super::{ExtensionNode, LeafNode, Node, NodeRef, ValueOrHash};
69

@@ -44,9 +47,13 @@ impl BranchNode {
4447
// Delegate to children if present
4548
let child_ref = &self.choices[choice];
4649
if child_ref.is_valid() {
47-
let child_node = child_ref
48-
.get_node(db, path.current())?
49-
.ok_or(TrieError::InconsistentTree)?;
50+
let child_node = child_ref.get_node(db, path.current())?.ok_or_else(|| {
51+
TrieError::InconsistentTree(InconsistentTreeError::NodeNotFoundOnBranchNode(
52+
child_ref.compute_hash().finalize(),
53+
self.compute_hash().finalize(),
54+
path.current(),
55+
))
56+
})?;
5057
child_node.get(db, path)
5158
} else {
5259
Ok(None)
@@ -67,6 +74,7 @@ impl BranchNode {
6774
// If path is at the end, insert or replace its own value.
6875
// Otherwise, check the corresponding choice and insert or delegate accordingly.
6976
if let Some(choice) = path.next_choice() {
77+
let current_node_hash = self.compute_hash().finalize();
7078
match (&mut self.choices[choice], value) {
7179
// Create new child (leaf node)
7280
(choice_ref, ValueOrHash::Value(value)) if !choice_ref.is_valid() => {
@@ -75,9 +83,15 @@ impl BranchNode {
7583
}
7684
// Insert into existing child and then update it
7785
(choice_ref, ValueOrHash::Value(value)) => {
78-
let child_node = choice_ref
79-
.get_node(db, path.current())?
80-
.ok_or(TrieError::InconsistentTree)?;
86+
let child_node = choice_ref.get_node(db, path.current())?.ok_or_else(|| {
87+
TrieError::InconsistentTree(
88+
InconsistentTreeError::NodeNotFoundOnBranchNode(
89+
choice_ref.compute_hash().finalize(),
90+
current_node_hash,
91+
path.current(),
92+
),
93+
)
94+
})?;
8195

8296
*choice_ref = child_node.insert(db, path, value)?.into();
8397
}
@@ -92,7 +106,15 @@ impl BranchNode {
92106
} else {
93107
*choice_ref = choice_ref
94108
.get_node(db, path.current())?
95-
.ok_or(TrieError::InconsistentTree)?
109+
.ok_or_else(|| {
110+
TrieError::InconsistentTree(
111+
InconsistentTreeError::NodeNotFoundOnBranchNode(
112+
choice_ref.compute_hash().finalize(),
113+
current_node_hash,
114+
path.current(),
115+
),
116+
)
117+
})?
96118
.insert(db, path, value)?
97119
.into();
98120
}
@@ -141,7 +163,15 @@ impl BranchNode {
141163
if self.choices[choice_index].is_valid() {
142164
let child_node = self.choices[choice_index]
143165
.get_node(db, path.current())?
144-
.ok_or(TrieError::InconsistentTree)?;
166+
.ok_or_else(|| {
167+
TrieError::InconsistentTree(
168+
InconsistentTreeError::NodeNotFoundOnBranchNode(
169+
self.choices[choice_index].compute_hash().finalize(),
170+
self.compute_hash().finalize(),
171+
path.current(),
172+
),
173+
)
174+
})?;
145175
// Remove value from child node
146176
let (child_node, old_value) = child_node.remove(db, path.clone())?;
147177
if let Some(child_node) = child_node {
@@ -182,7 +212,15 @@ impl BranchNode {
182212
let (choice_index, child_ref) = children[0];
183213
let child = child_ref
184214
.get_node(db, base_path.current().append_new(choice_index as u8))?
185-
.ok_or(TrieError::InconsistentTree)?;
215+
.ok_or_else(|| {
216+
TrieError::InconsistentTree(
217+
InconsistentTreeError::NodeNotFoundOnBranchNode(
218+
child_ref.compute_hash().finalize(),
219+
self.compute_hash().finalize(),
220+
base_path.current(),
221+
),
222+
)
223+
})?;
186224
match child {
187225
// Replace self with an extension node leading to the child
188226
Node::Branch(_) => ExtensionNode::new(
@@ -249,9 +287,13 @@ impl BranchNode {
249287
// Continue to child
250288
let child_ref = &self.choices[choice];
251289
if child_ref.is_valid() {
252-
let child_node = child_ref
253-
.get_node(db, path.current())?
254-
.ok_or(TrieError::InconsistentTree)?;
290+
let child_node = child_ref.get_node(db, path.current())?.ok_or_else(|| {
291+
TrieError::InconsistentTree(InconsistentTreeError::NodeNotFoundOnBranchNode(
292+
child_ref.compute_hash().finalize(),
293+
self.compute_hash().finalize(),
294+
path.current(),
295+
))
296+
})?;
255297
child_node.get_path(db, path, node_path)?;
256298
}
257299
}

crates/common/trie/node/extension.rs

Lines changed: 65 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@ use ethrex_rlp::structs::Encoder;
33
use crate::ValueRLP;
44
use crate::nibbles::Nibbles;
55
use crate::node_hash::NodeHash;
6-
use crate::{TrieDB, error::TrieError};
6+
use crate::{
7+
TrieDB,
8+
error::{ExtensionNodeErrorData, TrieError},
9+
};
710

811
use super::{BranchNode, Node, NodeRef, ValueOrHash};
912

@@ -26,10 +29,18 @@ impl ExtensionNode {
2629
// If the path is prefixed by this node's prefix, delegate to its child.
2730
// Otherwise, no value is present.
2831
if path.skip_prefix(&self.prefix) {
29-
let child_node = self
30-
.child
31-
.get_node(db, path.current())?
32-
.ok_or(TrieError::InconsistentTree)?;
32+
let child_node = self.child.get_node(db, path.current())?.ok_or_else(|| {
33+
TrieError::InconsistentTree(
34+
crate::InconsistentTreeError::NodeNotFoundOnExtensionNode(Box::new(
35+
ExtensionNodeErrorData {
36+
node_hash: self.child.compute_hash().finalize(),
37+
extension_node_hash: self.compute_hash().finalize(),
38+
extension_node_prefix: self.prefix.clone(),
39+
node_path: path.current(),
40+
},
41+
)),
42+
)
43+
})?;
3344

3445
child_node.get(db, path)
3546
} else {
@@ -58,14 +69,23 @@ impl ExtensionNode {
5869
if match_index == self.prefix.len() {
5970
let path = path.offset(match_index);
6071
// Insert into child node
61-
let child_node = self
62-
.child
63-
.get_node(db, path.current())?
64-
.ok_or(TrieError::InconsistentTree)?;
72+
let child_node = self.child.get_node(db, path.current())?.ok_or_else(|| {
73+
TrieError::InconsistentTree(
74+
crate::InconsistentTreeError::NodeNotFoundOnExtensionNode(Box::new(
75+
ExtensionNodeErrorData {
76+
node_hash: self.child.compute_hash().finalize(),
77+
extension_node_hash: self.compute_hash().finalize(),
78+
extension_node_prefix: self.prefix.clone(),
79+
node_path: path.current(),
80+
},
81+
)),
82+
)
83+
})?;
6584
let new_child_node = child_node.insert(db, path, value)?;
6685
self.child = new_child_node.into();
6786
Ok(self.into())
6887
} else if match_index == 0 {
88+
let current_node_hash = self.compute_hash().finalize();
6989
let new_node = if self.prefix.len() == 1 {
7090
self.child
7191
} else {
@@ -75,7 +95,18 @@ impl ExtensionNode {
7595
let branch_node = if self.prefix.at(0) == 16 {
7696
match new_node.get_node(db, path.current())? {
7797
Some(Node::Leaf(leaf)) => BranchNode::new_with_value(choices, leaf.value),
78-
_ => return Err(TrieError::InconsistentTree),
98+
_ => {
99+
return Err(TrieError::InconsistentTree(
100+
crate::InconsistentTreeError::ExtensionNodeInsertionError(Box::new(
101+
ExtensionNodeErrorData {
102+
node_hash: new_node.compute_hash().finalize(),
103+
extension_node_hash: current_node_hash,
104+
extension_node_prefix: self.prefix,
105+
node_path: path.current(),
106+
},
107+
)),
108+
));
109+
}
79110
}
80111
} else {
81112
choices[self.prefix.at(0)] = new_node;
@@ -106,10 +137,18 @@ impl ExtensionNode {
106137

107138
// Check if the value is part of the child subtrie according to the prefix
108139
if path.skip_prefix(&self.prefix) {
109-
let child_node = self
110-
.child
111-
.get_node(db, path.current())?
112-
.ok_or(TrieError::InconsistentTree)?;
140+
let child_node = self.child.get_node(db, path.current())?.ok_or_else(|| {
141+
TrieError::InconsistentTree(
142+
crate::InconsistentTreeError::NodeNotFoundOnExtensionNode(Box::new(
143+
ExtensionNodeErrorData {
144+
node_hash: self.child.compute_hash().finalize(),
145+
extension_node_hash: self.compute_hash().finalize(),
146+
extension_node_prefix: self.prefix.clone(),
147+
node_path: path.current(),
148+
},
149+
)),
150+
)
151+
})?;
113152
// Remove value from child subtrie
114153
let (child_node, old_value) = child_node.remove(db, path)?;
115154
// Restructure node based on removal
@@ -173,10 +212,18 @@ impl ExtensionNode {
173212
};
174213
// Continue to child
175214
if path.skip_prefix(&self.prefix) {
176-
let child_node = self
177-
.child
178-
.get_node(db, path.current())?
179-
.ok_or(TrieError::InconsistentTree)?;
215+
let child_node = self.child.get_node(db, path.current())?.ok_or_else(|| {
216+
TrieError::InconsistentTree(
217+
crate::InconsistentTreeError::NodeNotFoundOnExtensionNode(Box::new(
218+
ExtensionNodeErrorData {
219+
node_hash: self.child.clone().compute_hash().finalize(),
220+
extension_node_hash: self.compute_hash().finalize(),
221+
extension_node_prefix: self.prefix.clone(),
222+
node_path: path.current(),
223+
},
224+
)),
225+
)
226+
})?;
180227
child_node.get_path(db, path, node_path)?;
181228
}
182229
Ok(())

0 commit comments

Comments
 (0)