#![cfg_attr(not(feature = "std"), no_std)]
#![forbid(unsafe_code)]
extern crate alloc;
use core::fmt::Debug;
use digest::generic_array::GenericArray;
use digest::Digest;
use digest::OutputSizeUser;
use serde::{Deserialize, Serialize};
#[cfg(feature = "std")]
use thiserror::Error;
mod bytes32ext;
mod iterator;
mod node_type;
mod reader;
mod tree;
mod tree_cache;
mod types;
mod writer;
#[cfg(any(test, feature = "mocks"))]
pub mod mock;
pub mod restore;
use bytes32ext::Bytes32Ext;
pub use iterator::JellyfishMerkleIterator;
#[cfg(feature = "ics23")]
pub use tree::ics23_impl::ics23_spec;
pub use tree::JellyfishMerkleTree;
#[cfg(any(test, feature = "sha2"))]
pub use tree::Sha256Jmt;
use types::nibble::ROOT_NIBBLE_HEIGHT;
pub use types::proof;
pub use types::Version;
pub mod storage {
pub use node_type::{LeafNode, Node, NodeKey};
pub use reader::HasPreimage;
pub use reader::TreeReader;
pub use types::nibble::nibble_path::NibblePath;
pub use writer::{
NodeBatch, NodeStats, StaleNodeIndex, StaleNodeIndexBatch, TreeUpdateBatch, TreeWriter,
};
use super::*;
}
#[cfg(any(test))]
mod tests;
#[derive(Debug)]
#[cfg_attr(feature = "std", derive(Error))]
#[cfg_attr(
feature = "std",
error("Missing state root node at version {version}, probably pruned.")
)]
pub struct MissingRootError {
pub version: Version,
}
#[cfg(not(feature = "std"))]
impl core::fmt::Display for MissingRootError {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
write!(
f,
"Missing state root node at version {}, probably pruned.",
self.version
)
}
}
const SPARSE_MERKLE_PLACEHOLDER_HASH: [u8; 32] = *b"SPARSE_MERKLE_PLACEHOLDER_HASH__";
pub type OwnedValue = alloc::vec::Vec<u8>;
#[cfg(any(test))]
use proptest_derive::Arbitrary;
#[derive(
Copy,
Clone,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Serialize,
Deserialize,
borsh::BorshSerialize,
borsh::BorshDeserialize,
)]
#[cfg_attr(any(test), derive(Arbitrary))]
pub struct RootHash(pub [u8; 32]);
impl From<RootHash> for [u8; 32] {
fn from(value: RootHash) -> Self {
value.0
}
}
impl From<[u8; 32]> for RootHash {
fn from(value: [u8; 32]) -> Self {
Self(value)
}
}
impl AsRef<[u8]> for RootHash {
fn as_ref(&self) -> &[u8] {
&self.0
}
}
#[derive(
Copy,
Clone,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Serialize,
Deserialize,
borsh::BorshSerialize,
borsh::BorshDeserialize,
)]
#[cfg_attr(any(test), derive(Arbitrary))]
pub struct KeyHash(pub [u8; 32]);
#[derive(
Copy,
Clone,
PartialEq,
Eq,
PartialOrd,
Ord,
Hash,
Serialize,
Deserialize,
borsh::BorshSerialize,
borsh::BorshDeserialize,
)]
#[cfg_attr(any(test), derive(Arbitrary))]
#[doc(hidden)]
pub struct ValueHash(pub [u8; 32]);
impl ValueHash {
pub fn with<H: SimpleHasher>(value: impl AsRef<[u8]>) -> Self {
Self(H::hash(value))
}
}
impl KeyHash {
pub fn with<H: SimpleHasher>(key: impl AsRef<[u8]>) -> Self {
let key_hash = Self(H::hash(key.as_ref()));
tracing::debug!(key = ?EscapedByteSlice(key.as_ref()), ?key_hash, "hashed jmt key");
key_hash
}
}
impl core::fmt::Debug for KeyHash {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_tuple("KeyHash")
.field(&hex::encode(self.0))
.finish()
}
}
impl core::fmt::Debug for ValueHash {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_tuple("ValueHash")
.field(&hex::encode(self.0))
.finish()
}
}
impl core::fmt::Debug for RootHash {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
f.debug_tuple("RootHash")
.field(&hex::encode(self.0))
.finish()
}
}
struct EscapedByteSlice<'a>(&'a [u8]);
impl<'a> core::fmt::Debug for EscapedByteSlice<'a> {
fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result {
write!(f, "b\"")?;
for &b in self.0 {
#[allow(clippy::manual_range_contains)]
if b == b'\n' {
write!(f, "\\n")?;
} else if b == b'\r' {
write!(f, "\\r")?;
} else if b == b'\t' {
write!(f, "\\t")?;
} else if b == b'\\' || b == b'"' {
write!(f, "\\{}", b as char)?;
} else if b == b'\0' {
write!(f, "\\0")?;
} else if b >= 0x20 && b < 0x7f {
write!(f, "{}", b as char)?;
} else {
write!(f, "\\x{:02x}", b)?;
}
}
write!(f, "\"")?;
Ok(())
}
}
pub trait SimpleHasher: Sized {
fn new() -> Self;
fn update(&mut self, data: &[u8]);
fn finalize(self) -> [u8; 32];
fn hash(data: impl AsRef<[u8]>) -> [u8; 32] {
let mut hasher = Self::new();
hasher.update(data.as_ref());
hasher.finalize()
}
}
impl<T: Digest> SimpleHasher for T
where
[u8; 32]: From<GenericArray<u8, <T as OutputSizeUser>::OutputSize>>,
{
fn new() -> Self {
<T as Digest>::new()
}
fn update(&mut self, data: &[u8]) {
self.update(data)
}
fn finalize(self) -> [u8; 32] {
self.finalize().into()
}
}
pub struct TransparentHasher {
key: [u8; 32],
}
impl SimpleHasher for TransparentHasher {
fn new() -> Self {
TransparentHasher { key: [0u8; 32] }
}
fn update(&mut self, data: &[u8]) {
for (dest, &src) in self.key.iter_mut().zip(data.iter()) {
*dest = src;
}
}
fn finalize(self) -> [u8; 32] {
self.key
}
}