Skip to content
LogoLogo

Errors

Every fallible MerkleForge API returns Result<T, MerkleError>. Verification functions return bool instead: a bad proof is an expected outcome, not an error.

MerkleError lives in merkle_core::error (and the prelude). It implements Debug, Clone, PartialEq, Eq, Display, and, with the default std feature, std::error::Error, so it works with ?, Box<dyn Error>, anyhow, and thiserror.

Variants

VariantRaised when
EmptyTreeProof generation (or binary remove) on a tree with no leaves
IndexOutOfBounds { index, len }A LeafIndex past the last logical leaf
InvalidProofAvailable to APIs that report failed verification as an error (the shipped verifiers return false instead)
InvalidProofStructure(String)A proof's shape is inconsistent (e.g. sparse proof generation with a non-256 depth)
EmptyLeafDataInserting an empty value (empty data would be indistinguishable from padding)
SerializationError(String)to_bytes failed
DeserializationError(String)from_bytes got malformed data
HashError(String)An internal hashing step failed (for custom adapters; not raised by the shipped ones)
UnsupportedOperation(&'static str)The variant can't do this, e.g. removing a missing sparse or Patricia key, or index-based Patricia proofs
RlpError(String)Malformed RLP or hex-prefix data in the Patricia trie

Handling errors

MerkleError is #[non_exhaustive]: new variants may arrive in minor releases, so keep a fallback arm.

use merkle_core::prelude::*;
use merkle_variants::BinaryMerkleTree;
use merkleforge_hash::Sha256;
 
fn describe(result: Result<MerkleProof<[u8; 32]>, MerkleError>) -> String {
    match result {
        Ok(proof) => format!("proof with {} siblings", proof.depth()),
        Err(MerkleError::EmptyTree) => "tree has no leaves".into(),
        Err(MerkleError::IndexOutOfBounds { index, len }) => {
            format!("leaf {index} is outside the current leaf count {len}")
        }
        Err(MerkleError::EmptyLeafData) => "empty leaves are rejected".into(),
        Err(other) => other.to_string(),
    }
}
 
fn main() -> Result<(), MerkleError> {
    let mut tree = BinaryMerkleTree::<Sha256>::new();
    assert_eq!(describe(tree.generate_proof(LeafIndex(0))), "tree has no leaves");
 
    tree.insert(b"alice")?;
    assert_eq!(
        describe(tree.generate_proof(LeafIndex(3))),
        "leaf 3 is outside the current leaf count 1",
    );
    assert_eq!(describe(tree.generate_proof(LeafIndex(0))), "proof with 0 siblings");
    Ok(())
}

Display messages

use merkle_core::error::MerkleError;
 
fn main() {
    let err = MerkleError::IndexOutOfBounds { index: 5, len: 3 };
    assert_eq!(err.to_string(), "index 5 is out of bounds for a tree with 3 leaves");
    assert_eq!(MerkleError::EmptyLeafData.to_string(), "leaf data must not be empty");
}

Using with Box<dyn Error>

use std::error::Error;
 
use merkle_variants::MerklePatriciaTrie;
use merkleforge_hash::Keccak256;
 
fn main() -> Result<(), Box<dyn Error>> {
    let mut trie = MerklePatriciaTrie::<Keccak256>::new();
    trie.insert(b"key", b"value")?;
 
    // Removing a key that isn't there is an error.
    let err = trie.remove(b"missing").unwrap_err();
    println!("{err}");
    Ok(())
}