Skip to content
Open
Show file tree
Hide file tree
Changes from all 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: 6 additions & 4 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions crates/imt/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -8,4 +8,5 @@ description = "Incremental Merkle Tree"

[dependencies]
hex = "0.4.3"
thiserror = "2"
tiny-keccak = { version = "2.0.0", features = ["keccak"] }
16 changes: 16 additions & 0 deletions crates/imt/src/errors.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
use thiserror::Error;
Comment thread
protocolwhisper marked this conversation as resolved.

#[derive(Error, Debug, PartialEq, Eq)]
pub enum ImtError {
#[error("Too many leaves: got {got}, max for arity {arity} and depth {depth} is max {max}")]

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

not a blocker but there's a redundant "max" word here

TooManyLeaves {
got: usize,
arity: usize,
depth: usize,
max: usize,
},
#[error("The tree is full")]
TreeFull,
#[error("The leaf does not exist in this tree")]
NotContained,
}
29 changes: 19 additions & 10 deletions crates/imt/src/imt.rs
Original file line number Diff line number Diff line change
@@ -1,3 +1,5 @@
use crate::errors::ImtError;

pub struct IMT {
nodes: Vec<Vec<IMTNode>>,
zeroes: Vec<IMTNode>,
Expand All @@ -23,9 +25,16 @@ impl IMT {
zero_value: IMTNode,
arity: usize,
leaves: Vec<IMTNode>,
) -> Result<IMT, &'static str> {
if leaves.len() > arity.pow(depth as u32) {
return Err("The tree cannot contain more than arity^depth leaves");
) -> Result<IMT, ImtError> {

@0x471 0x471 Mar 23, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

This is a breaking change since SMTError import path changes and InvalidParameterType variant shape change from tuple to named fields.

How should we approach this? @vplasencia

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

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

For this what about we use #[deprecated(note = "Use new_with_error instead")] ?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

I think it doesn't apply here since you can't deprecate a variant shape change, and there's no new_with_error method?

Let's confirm with Vivian how to approach these kind of breaking changes

let got = leaves.len();
let max = arity.pow(depth as u32);
if got > max {
return Err(ImtError::TooManyLeaves {
got,
arity,
depth,
max,
});
}

let mut imt = IMT {
Expand Down Expand Up @@ -93,19 +102,19 @@ impl IMT {
self.nodes.get(0)?.iter().position(|n| n == &leaf)
}

pub fn insert(&mut self, leaf: IMTNode) -> Result<(), &'static str> {
pub fn insert(&mut self, leaf: IMTNode) -> Result<(), ImtError> {
if self.nodes[0].len() >= self.arity.pow(self.depth as u32) {
return Err("The tree is full");
return Err(ImtError::TreeFull);
}

let index = self.nodes[0].len();
self.nodes[0].push(leaf);
self.update(index, self.nodes[0][index].clone())
}

pub fn update(&mut self, mut index: usize, new_leaf: IMTNode) -> Result<(), &'static str> {
pub fn update(&mut self, mut index: usize, new_leaf: IMTNode) -> Result<(), ImtError> {
if index >= self.nodes[0].len() {
return Err("The leaf does not exist in this tree");
return Err(ImtError::NotContained);
}

let mut node = new_leaf;
Expand Down Expand Up @@ -138,13 +147,13 @@ impl IMT {
Ok(())
}

pub fn delete(&mut self, index: usize) -> Result<(), &'static str> {
pub fn delete(&mut self, index: usize) -> Result<(), ImtError> {
self.update(index, self.zeroes[0].clone())
}

pub fn create_proof(&self, index: usize) -> Result<IMTMerkleProof, &'static str> {
pub fn create_proof(&self, index: usize) -> Result<IMTMerkleProof, ImtError> {
if index >= self.nodes[0].len() {
return Err("The leaf does not exist in this tree");
return Err(ImtError::NotContained);
}

let mut siblings = Vec::with_capacity(self.depth);
Expand Down
3 changes: 3 additions & 0 deletions crates/imt/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
pub mod errors;
pub mod hash;
Comment thread
protocolwhisper marked this conversation as resolved.
pub mod imt;

pub use errors::ImtError;
1 change: 1 addition & 0 deletions crates/smt/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -10,3 +10,4 @@ description = "Sparse Merkle Tree"

[dependencies]
num-bigint = "0.4.6"
thiserror = "2"
13 changes: 13 additions & 0 deletions crates/smt/src/errors.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
use thiserror::Error;
Comment thread
protocolwhisper marked this conversation as resolved.

#[derive(Error, Debug, PartialEq, Eq)]
pub enum SMTError {
#[error("Key {0} already exists")]
KeyAlreadyExist(String),
#[error("Key {0} does not exist")]
KeyDoesNotExist(String),
#[error("Parameter {name} must be a {expected_type}")]
InvalidParameterType { name: String, expected_type: String },
#[error("Invalid sibling index")]
InvalidSiblingIndex,
}
3 changes: 3 additions & 0 deletions crates/smt/src/lib.rs
Original file line number Diff line number Diff line change
@@ -1,2 +1,5 @@
pub mod errors;
pub mod smt;
Comment thread
protocolwhisper marked this conversation as resolved.
mod utils;

pub use errors::SMTError;
32 changes: 5 additions & 27 deletions crates/smt/src/smt.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,13 @@ use std::{collections::HashMap, str::FromStr};

use num_bigint::BigInt;

pub use crate::errors::SMTError;
use crate::utils::{
get_first_common_elements, get_index_of_last_non_zero_element, is_hexadecimal, key_to_path,
};

use std::fmt;

#[derive(Debug, PartialEq)]
pub enum SMTError {
Comment thread
protocolwhisper marked this conversation as resolved.
KeyAlreadyExist(String),
KeyDoesNotExist(String),
InvalidParameterType(String, String),
InvalidSiblingIndex,
}

impl fmt::Display for SMTError {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
SMTError::KeyAlreadyExist(s) => write!(f, "Key {} already exists", s),
SMTError::KeyDoesNotExist(s) => write!(f, "Key {} does not exist", s),
SMTError::InvalidParameterType(p, t) => {
write!(f, "Parameter {} must be a {}", p, t)
},
SMTError::InvalidSiblingIndex => write!(f, "Invalid sibling index"),
}
}
}

impl std::error::Error for SMTError {}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Node {
Str(String),
Expand All @@ -55,10 +33,10 @@ impl FromStr for Node {
} else if is_hexadecimal(s) {
Ok(Node::Str(s.to_string()))
} else {
Err(SMTError::InvalidParameterType(
s.to_string(),
"BigInt or hexadecimal string".to_string(),
))
Err(SMTError::InvalidParameterType {
name: s.to_string(),
expected_type: "BigInt or hexadecimal string".to_string(),
})
}
}
}
Expand Down