Skip to content

Commit 078eafa

Browse files
committed
tree: 🍉 JellyfishMerkleTree::get_with_exclusion_proof() uses LookupError
this introduces some additional variants to `LookupError<E>`, and transforms `get_with_exclusion_proof()` s.t. it now returns a typed `LookupError<E>` as well. some documentation is also added to the function, while we are here.
1 parent 2c4357a commit 078eafa

File tree

1 file changed

+80
-42
lines changed

1 file changed

+80
-42
lines changed

‎src/tree.rs

+80-42
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
use crate::{
22
node_type::{Child, Children, InternalNode, LeafNode, Node, NodeKey, NodeType},
33
proof::{definition::UpdateMerkleProof, SparseMerkleLeafNode, SparseMerkleNode},
4-
storage::{Node::Leaf, TreeReader, TreeReaderExt, TreeUpdateBatch},
4+
storage::{Node::Leaf, TreeReader, TreeUpdateBatch},
55
tree_cache::{FreezeError, NodeAlreadyExists, TreeCache},
66
types::{
77
nibble::{
@@ -14,7 +14,7 @@ use crate::{
1414
Bytes32Ext, KeyHash, MissingRootError, OwnedValue, RootHash, SimpleHasher, ValueHash,
1515
};
1616
use alloc::{collections::BTreeMap, vec, vec::Vec};
17-
use anyhow::{bail, format_err};
17+
use anyhow::format_err;
1818
use core::{cmp::Ordering, convert::TryInto, marker::PhantomData};
1919

2020
#[cfg(not(feature = "std"))]
@@ -57,8 +57,17 @@ pub enum LookupError<E> {
5757
ValueNotFound { version: u64, key_hash: KeyHash },
5858
#[error("Non-root null node exists with node key {key:?}")]
5959
NonRootNullNodeExists { key: NodeKey },
60+
#[error("Internal node has no children")]
61+
InternalNodeHasNoChildren,
6062
#[error("Jellyfish Merkle tree has cyclic graph inside.")]
6163
CyclicGraphDetected,
64+
#[error("Found exact key when searching for bounding path for nonexistence proof")]
65+
FoundKeyInBoundingPath,
66+
#[error("Invalid exclusion proof")]
67+
ExclusionProofIsNotValid,
68+
// Some actions might fail because the tree is empty.
69+
#[error("{msg}")]
70+
TreeIsEmpty { msg: &'static str },
6271
}
6372

6473
/// Errors that can occur when a value set is [applied] to a [`JellyfishMerkleTree<'a, R, H>`].
@@ -1145,7 +1154,7 @@ where
11451154
extreme: Extreme,
11461155
to: NibblePath,
11471156
parents: Vec<InternalNode>,
1148-
) -> Result<Option<KeyHash>, anyhow::Error> {
1157+
) -> Result<Option<KeyHash>, LookupError<R::Error>> {
11491158
fn neighbor_nibble(
11501159
node: &InternalNode,
11511160
child_index: Nibble,
@@ -1190,27 +1199,35 @@ where
11901199
&self,
11911200
version: Version,
11921201
search_key: KeyHash,
1193-
) -> Result<SearchResult, anyhow::Error> {
1202+
) -> Result<SearchResult, LookupError<R::Error>> {
11941203
let search_path = NibblePath::new(search_key.0.to_vec());
11951204
let mut search_nibbles = search_path.nibbles();
11961205
let mut next_node_key = NodeKey::new_empty_path(version);
11971206
let mut internal_nodes = vec![];
11981207

11991208
for nibble_depth in 0..=ROOT_NIBBLE_HEIGHT {
1200-
let next_node = self.reader.get_node(&next_node_key).map_err(|err| {
1201-
if nibble_depth == 0 {
1202-
anyhow::anyhow!(MissingRootError { version })
1203-
} else {
1204-
err
1205-
}
1206-
})?;
1209+
let next_node = self
1210+
.reader
1211+
.get_node_option(&next_node_key)
1212+
.map_err(LookupError::Read)?
1213+
.ok_or_else(|| {
1214+
if nibble_depth == 0 {
1215+
// If this is the first loop iteration, we are missing our root.
1216+
LookupError::RootMissing(MissingRootError { version })
1217+
} else {
1218+
// Otherwise, we are missing some other node.
1219+
LookupError::NodeMissing {
1220+
nibble_depth,
1221+
key: next_node_key.clone(),
1222+
}
1223+
}
1224+
})?;
12071225

12081226
match next_node {
12091227
Node::Internal(node) => {
12101228
internal_nodes.push(node.clone());
1211-
let queried_child_index = search_nibbles
1212-
.next()
1213-
.ok_or_else(|| format_err!("ran out of nibbles"))?;
1229+
let queried_child_index =
1230+
search_nibbles.next().ok_or(LookupError::RanOutOfNibbles)?;
12141231

12151232
let child_node_key =
12161233
node.get_only_child_without_siblings(&next_node_key, queried_child_index);
@@ -1240,27 +1257,25 @@ where
12401257
}
12411258
Node::Null => {
12421259
if nibble_depth == 0 {
1243-
bail!(
1244-
"Cannot manufacture nonexistence proof by exclusion for the empty tree"
1245-
);
1260+
return Err(LookupError::TreeIsEmpty {
1261+
msg: "Cannot manufacture nonexistence proof by exclusion for the \
1262+
empty tree",
1263+
});
12461264
} else {
1247-
bail!(
1248-
"Non-root null node exists with node key {:?}",
1249-
next_node_key
1250-
);
1265+
return Err(LookupError::NonRootNullNodeExists { key: next_node_key });
12511266
}
12521267
}
12531268
}
12541269
}
12551270

1256-
bail!("Jellyfish Merkle tree has cyclic graph inside.");
1271+
return Err(LookupError::CyclicGraphDetected);
12571272
}
12581273

12591274
fn get_bounding_path(
12601275
&self,
12611276
search_key: KeyHash,
12621277
version: Version,
1263-
) -> Result<(Option<KeyHash>, Option<KeyHash>), anyhow::Error> {
1278+
) -> Result<(Option<KeyHash>, Option<KeyHash>), LookupError<R::Error>> {
12641279
let search_result = self.search_for_closest_node(version, search_key)?;
12651280

12661281
match search_result {
@@ -1295,7 +1310,7 @@ where
12951310
Ok((rightmost_left_keyhash, Some(leaf_hash)))
12961311
}
12971312
Ordering::Equal => {
1298-
bail!("found exact key when searching for bounding path for nonexistence proof")
1313+
return Err(LookupError::FoundKeyInBoundingPath);
12991314
}
13001315
}
13011316
}
@@ -1321,12 +1336,21 @@ where
13211336
}
13221337
}
13231338

1324-
/// Returns the value (if applicable) and the corresponding merkle proof.
1339+
/// Returns the [value] (if applicable) and the corresponding [merkle proof].
1340+
///
1341+
/// - Returns a tuple `Ok(Ok((value, proof)))` if a value associated with the given key exists.
1342+
/// - Returns an [`ExclusionProof<H>`] as `Ok(Err(exclusion_proof))` if no value associated
1343+
/// with the given key exists.
1344+
/// - Returns `Err(e)` if an unexpected error was encountered while retrieving the value.
1345+
///
1346+
/// [value]: OwnedValue
1347+
/// [merkle proof]: SparseMerkleProof
13251348
pub fn get_with_exclusion_proof(
13261349
&self,
13271350
key_hash: KeyHash,
13281351
version: Version,
1329-
) -> Result<Result<(OwnedValue, SparseMerkleProof<H>), ExclusionProof<H>>, anyhow::Error> {
1352+
) -> Result<Result<(OwnedValue, SparseMerkleProof<H>), ExclusionProof<H>>, LookupError<R::Error>>
1353+
{
13301354
// Optimistically attempt get_with_proof, if that succeeds, we're done.
13311355
if let (Some(value), proof) = self.get_with_proof(key_hash, version)? {
13321356
return Ok(Ok((value, proof)));
@@ -1361,7 +1385,7 @@ where
13611385
leftmost_right_proof: right_proof,
13621386
}))
13631387
}
1364-
_ => bail!("Invalid exclusion proof"),
1388+
_ => return Err(LookupError::ExclusionProofIsNotValid),
13651389
}
13661390
}
13671391

@@ -1371,7 +1395,7 @@ where
13711395
mut node_key: NodeKey,
13721396
nibble_depth: usize,
13731397
extreme: Extreme,
1374-
) -> Result<KeyHash, anyhow::Error> {
1398+
) -> Result<KeyHash, LookupError<R::Error>> {
13751399
// Depending on the extreme specified, get either the least nibble or the most nibble
13761400
let min_or_max = |internal_node: &InternalNode| {
13771401
match extreme {
@@ -1384,13 +1408,22 @@ where
13841408
// We limit the number of loops here deliberately to avoid potential cyclic graph bugs
13851409
// in the tree structure.
13861410
for nibble_depth in nibble_depth..=ROOT_NIBBLE_HEIGHT {
1387-
let node = self.reader.get_node(&node_key).map_err(|err| {
1388-
if nibble_depth == 0 {
1389-
anyhow::anyhow!(MissingRootError { version })
1390-
} else {
1391-
err
1392-
}
1393-
})?;
1411+
let node = self
1412+
.reader
1413+
.get_node_option(&node_key)
1414+
.map_err(LookupError::Read)?
1415+
.ok_or_else(|| {
1416+
if nibble_depth == 0 {
1417+
// If this is the first loop iteration, we are missing our root.
1418+
LookupError::RootMissing(MissingRootError { version })
1419+
} else {
1420+
// Otherwise, we are missing some other node.
1421+
LookupError::NodeMissing {
1422+
nibble_depth,
1423+
key: node_key.clone(),
1424+
}
1425+
}
1426+
})?;
13941427
match node {
13951428
Node::Internal(internal_node) => {
13961429
// Find the leftmost nibble in the children
@@ -1401,18 +1434,23 @@ where
14011434
// Proceed downwards
14021435
node_key = match child_node_key {
14031436
Some(node_key) => node_key,
1404-
None => {
1405-
bail!("Internal node has no children");
1406-
}
1437+
None => return Err(LookupError::InternalNodeHasNoChildren),
14071438
};
14081439
}
1409-
Node::Leaf(leaf_node) => {
1410-
return Ok(leaf_node.key_hash());
1440+
Node::Leaf(leaf_node) => return Ok(leaf_node.key_hash()),
1441+
Node::Null => {
1442+
if nibble_depth == 0 {
1443+
return Err(LookupError::TreeIsEmpty {
1444+
msg: "Null node cannot have children",
1445+
});
1446+
} else {
1447+
return Err(LookupError::NonRootNullNodeExists { key: node_key });
1448+
}
14111449
}
1412-
Node::Null => bail!("Null node cannot have children"),
14131450
}
14141451
}
1415-
bail!("Jellyfish Merkle tree has cyclic graph inside.");
1452+
1453+
return Err(LookupError::CyclicGraphDetected);
14161454
}
14171455

14181456
fn get_without_proof(

0 commit comments

Comments
 (0)