Skip to content

Commit aa51392

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 7e7d1f2 commit aa51392

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"))]
@@ -56,8 +56,17 @@ pub enum LookupError<E> {
5656
ValueNotFound { version: u64, key_hash: KeyHash },
5757
#[error("Non-root null node exists with node key {key:?}")]
5858
NonRootNullNodeExists { key: NodeKey },
59+
#[error("Internal node has no children")]
60+
InternalNodeHasNoChildren,
5961
#[error("Jellyfish Merkle tree has cyclic graph inside.")]
6062
CyclicGraphDetected,
63+
#[error("Found exact key when searching for bounding path for nonexistence proof")]
64+
FoundKeyInBoundingPath,
65+
#[error("Invalid exclusion proof")]
66+
ExclusionProofIsNotValid,
67+
// Some actions might fail because the tree is empty.
68+
#[error("{msg}")]
69+
TreeIsEmpty { msg: &'static str },
6170
}
6271

6372
/// Errors that can occur when a value set is [applied] to a [`JellyfishMerkleTree<'a, R, H>`].
@@ -1143,7 +1152,7 @@ where
11431152
extreme: Extreme,
11441153
to: NibblePath,
11451154
parents: Vec<InternalNode>,
1146-
) -> Result<Option<KeyHash>, anyhow::Error> {
1155+
) -> Result<Option<KeyHash>, LookupError<R::Error>> {
11471156
fn neighbor_nibble(
11481157
node: &InternalNode,
11491158
child_index: Nibble,
@@ -1188,27 +1197,35 @@ where
11881197
&self,
11891198
version: Version,
11901199
search_key: KeyHash,
1191-
) -> Result<SearchResult, anyhow::Error> {
1200+
) -> Result<SearchResult, LookupError<R::Error>> {
11921201
let search_path = NibblePath::new(search_key.0.to_vec());
11931202
let mut search_nibbles = search_path.nibbles();
11941203
let mut next_node_key = NodeKey::new_empty_path(version);
11951204
let mut internal_nodes = vec![];
11961205

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

12061224
match next_node {
12071225
Node::Internal(node) => {
12081226
internal_nodes.push(node.clone());
1209-
let queried_child_index = search_nibbles
1210-
.next()
1211-
.ok_or_else(|| format_err!("ran out of nibbles"))?;
1227+
let queried_child_index =
1228+
search_nibbles.next().ok_or(LookupError::RanOutOfNibbles)?;
12121229

12131230
let child_node_key =
12141231
node.get_only_child_without_siblings(&next_node_key, queried_child_index);
@@ -1238,27 +1255,25 @@ where
12381255
}
12391256
Node::Null => {
12401257
if nibble_depth == 0 {
1241-
bail!(
1242-
"Cannot manufacture nonexistence proof by exclusion for the empty tree"
1243-
);
1258+
return Err(LookupError::TreeIsEmpty {
1259+
msg: "Cannot manufacture nonexistence proof by exclusion for the \
1260+
empty tree",
1261+
});
12441262
} else {
1245-
bail!(
1246-
"Non-root null node exists with node key {:?}",
1247-
next_node_key
1248-
);
1263+
return Err(LookupError::NonRootNullNodeExists { key: next_node_key });
12491264
}
12501265
}
12511266
}
12521267
}
12531268

1254-
bail!("Jellyfish Merkle tree has cyclic graph inside.");
1269+
return Err(LookupError::CyclicGraphDetected);
12551270
}
12561271

12571272
fn get_bounding_path(
12581273
&self,
12591274
search_key: KeyHash,
12601275
version: Version,
1261-
) -> Result<(Option<KeyHash>, Option<KeyHash>), anyhow::Error> {
1276+
) -> Result<(Option<KeyHash>, Option<KeyHash>), LookupError<R::Error>> {
12621277
let search_result = self.search_for_closest_node(version, search_key)?;
12631278

12641279
match search_result {
@@ -1293,7 +1308,7 @@ where
12931308
Ok((rightmost_left_keyhash, Some(leaf_hash)))
12941309
}
12951310
Ordering::Equal => {
1296-
bail!("found exact key when searching for bounding path for nonexistence proof")
1311+
return Err(LookupError::FoundKeyInBoundingPath);
12971312
}
12981313
}
12991314
}
@@ -1319,12 +1334,21 @@ where
13191334
}
13201335
}
13211336

1322-
/// Returns the value (if applicable) and the corresponding merkle proof.
1337+
/// Returns the [value] (if applicable) and the corresponding [merkle proof].
1338+
///
1339+
/// - Returns a tuple `Ok(Ok((value, proof)))` if a value associated with the given key exists.
1340+
/// - Returns an [`ExclusionProof<H>`] as `Ok(Err(exclusion_proof))` if no value associated
1341+
/// with the given key exists.
1342+
/// - Returns `Err(e)` if an unexpected error was encountered while retrieving the value.
1343+
///
1344+
/// [value]: OwnedValue
1345+
/// [merkle proof]: SparseMerkleProof
13231346
pub fn get_with_exclusion_proof(
13241347
&self,
13251348
key_hash: KeyHash,
13261349
version: Version,
1327-
) -> Result<Result<(OwnedValue, SparseMerkleProof<H>), ExclusionProof<H>>, anyhow::Error> {
1350+
) -> Result<Result<(OwnedValue, SparseMerkleProof<H>), ExclusionProof<H>>, LookupError<R::Error>>
1351+
{
13281352
// Optimistically attempt get_with_proof, if that succeeds, we're done.
13291353
if let (Some(value), proof) = self.get_with_proof(key_hash, version)? {
13301354
return Ok(Ok((value, proof)));
@@ -1359,7 +1383,7 @@ where
13591383
leftmost_right_proof: right_proof,
13601384
}))
13611385
}
1362-
_ => bail!("Invalid exclusion proof"),
1386+
_ => return Err(LookupError::ExclusionProofIsNotValid),
13631387
}
13641388
}
13651389

@@ -1369,7 +1393,7 @@ where
13691393
mut node_key: NodeKey,
13701394
nibble_depth: usize,
13711395
extreme: Extreme,
1372-
) -> Result<KeyHash, anyhow::Error> {
1396+
) -> Result<KeyHash, LookupError<R::Error>> {
13731397
// Depending on the extreme specified, get either the least nibble or the most nibble
13741398
let min_or_max = |internal_node: &InternalNode| {
13751399
match extreme {
@@ -1382,13 +1406,22 @@ where
13821406
// We limit the number of loops here deliberately to avoid potential cyclic graph bugs
13831407
// in the tree structure.
13841408
for nibble_depth in nibble_depth..=ROOT_NIBBLE_HEIGHT {
1385-
let node = self.reader.get_node(&node_key).map_err(|err| {
1386-
if nibble_depth == 0 {
1387-
anyhow::anyhow!(MissingRootError { version })
1388-
} else {
1389-
err
1390-
}
1391-
})?;
1409+
let node = self
1410+
.reader
1411+
.get_node_option(&node_key)
1412+
.map_err(LookupError::Read)?
1413+
.ok_or_else(|| {
1414+
if nibble_depth == 0 {
1415+
// If this is the first loop iteration, we are missing our root.
1416+
LookupError::RootMissing(MissingRootError { version })
1417+
} else {
1418+
// Otherwise, we are missing some other node.
1419+
LookupError::NodeMissing {
1420+
nibble_depth,
1421+
key: node_key.clone(),
1422+
}
1423+
}
1424+
})?;
13921425
match node {
13931426
Node::Internal(internal_node) => {
13941427
// Find the leftmost nibble in the children
@@ -1399,18 +1432,23 @@ where
13991432
// Proceed downwards
14001433
node_key = match child_node_key {
14011434
Some(node_key) => node_key,
1402-
None => {
1403-
bail!("Internal node has no children");
1404-
}
1435+
None => return Err(LookupError::InternalNodeHasNoChildren),
14051436
};
14061437
}
1407-
Node::Leaf(leaf_node) => {
1408-
return Ok(leaf_node.key_hash());
1438+
Node::Leaf(leaf_node) => return Ok(leaf_node.key_hash()),
1439+
Node::Null => {
1440+
if nibble_depth == 0 {
1441+
return Err(LookupError::TreeIsEmpty {
1442+
msg: "Null node cannot have children",
1443+
});
1444+
} else {
1445+
return Err(LookupError::NonRootNullNodeExists { key: node_key });
1446+
}
14091447
}
1410-
Node::Null => bail!("Null node cannot have children"),
14111448
}
14121449
}
1413-
bail!("Jellyfish Merkle tree has cyclic graph inside.");
1450+
1451+
return Err(LookupError::CyclicGraphDetected);
14141452
}
14151453

14161454
fn get_without_proof(

0 commit comments

Comments
 (0)