Skip to main content

miden_client/rpc/domain/
merkle.rs

1use alloc::vec::Vec;
2
3use miden_protocol::Word;
4use miden_protocol::crypto::merkle::mmr::{Forest, MmrDelta};
5use miden_protocol::crypto::merkle::{MerklePath, SparseMerklePath};
6
7use crate::rpc::errors::RpcConversionError;
8use crate::rpc::generated as proto;
9
10// CONSTANTS
11// ================================================================================================
12
13/// The maximum number of siblings a [`MerklePath`] can hold. `MerklePath` represents its depth as
14/// a `u8`, so a longer path is not representable.
15const MAX_MERKLE_PATH_SIBLINGS: usize = u8::MAX as usize;
16
17// MERKLE PATH
18// ================================================================================================
19
20impl From<MerklePath> for proto::primitives::MerklePath {
21    fn from(value: MerklePath) -> Self {
22        (&value).into()
23    }
24}
25
26impl From<&MerklePath> for proto::primitives::MerklePath {
27    fn from(value: &MerklePath) -> Self {
28        let siblings = value.nodes().iter().map(proto::primitives::Digest::from).collect();
29        proto::primitives::MerklePath { siblings }
30    }
31}
32
33impl TryFrom<&proto::primitives::MerklePath> for MerklePath {
34    type Error = RpcConversionError;
35
36    fn try_from(merkle_path: &proto::primitives::MerklePath) -> Result<Self, Self::Error> {
37        // `MerklePath` enforces this bound with an assertion, so the count has to be checked here
38        // for the conversion to stay fallible on an oversized response.
39        if merkle_path.siblings.len() > MAX_MERKLE_PATH_SIBLINGS {
40            return Err(RpcConversionError::InvalidField(format!(
41                "MerklePath has {} siblings but at most {MAX_MERKLE_PATH_SIBLINGS} are allowed",
42                merkle_path.siblings.len(),
43            )));
44        }
45
46        merkle_path.siblings.iter().map(Word::try_from).collect()
47    }
48}
49
50impl TryFrom<proto::primitives::MerklePath> for MerklePath {
51    type Error = RpcConversionError;
52
53    fn try_from(merkle_path: proto::primitives::MerklePath) -> Result<Self, Self::Error> {
54        MerklePath::try_from(&merkle_path)
55    }
56}
57
58// SPARSE MERKLE PATH
59
60// ================================================================================================
61
62impl From<SparseMerklePath> for proto::primitives::SparseMerklePath {
63    fn from(value: SparseMerklePath) -> Self {
64        let (empty_nodes_mask, siblings) = value.into_parts();
65
66        proto::primitives::SparseMerklePath {
67            empty_nodes_mask,
68
69            siblings: siblings.into_iter().map(proto::primitives::Digest::from).collect(),
70        }
71    }
72}
73
74impl TryFrom<proto::primitives::SparseMerklePath> for SparseMerklePath {
75    type Error = RpcConversionError;
76
77    fn try_from(merkle_path: proto::primitives::SparseMerklePath) -> Result<Self, Self::Error> {
78        Ok(SparseMerklePath::from_parts(
79            merkle_path.empty_nodes_mask,
80            merkle_path
81                .siblings
82                .into_iter()
83                .map(Word::try_from)
84                .collect::<Result<Vec<_>, _>>()?,
85        )?)
86    }
87}
88
89// MMR DELTA
90// ================================================================================================
91
92impl TryFrom<MmrDelta> for proto::primitives::MmrDelta {
93    type Error = RpcConversionError;
94
95    fn try_from(value: MmrDelta) -> Result<Self, Self::Error> {
96        let data = value.data.into_iter().map(proto::primitives::Digest::from).collect();
97        Ok(proto::primitives::MmrDelta {
98            forest: u64::try_from(value.forest.num_leaves())?,
99            data,
100        })
101    }
102}
103
104impl TryFrom<proto::primitives::MmrDelta> for MmrDelta {
105    type Error = RpcConversionError;
106
107    fn try_from(value: proto::primitives::MmrDelta) -> Result<Self, Self::Error> {
108        let data: Result<Vec<_>, RpcConversionError> =
109            value.data.into_iter().map(Word::try_from).collect();
110
111        let num_leaves = usize::try_from(value.forest).map_err(|_| {
112            RpcConversionError::InvalidField("MmrDelta forest value exceeds usize".into())
113        })?;
114        Ok(MmrDelta {
115            forest: Forest::new(num_leaves)
116                .map_err(|_| RpcConversionError::InvalidField("MmrDelta forest invalid".into()))?,
117            data: data?,
118        })
119    }
120}
121
122// TESTS
123// ================================================================================================
124
125#[cfg(test)]
126mod tests {
127    use super::*;
128
129    fn proto_merkle_path(siblings: usize) -> proto::primitives::MerklePath {
130        proto::primitives::MerklePath {
131            siblings: vec![proto::primitives::Digest::default(); siblings],
132        }
133    }
134
135    #[test]
136    fn merkle_path_conversion_accepts_the_maximum_sibling_count() {
137        let path = MerklePath::try_from(&proto_merkle_path(MAX_MERKLE_PATH_SIBLINGS))
138            .expect("the maximum sibling count must convert");
139
140        assert_eq!(path.depth(), u8::MAX);
141    }
142
143    #[test]
144    fn merkle_path_conversion_rejects_an_oversized_sibling_count() {
145        let oversized = proto_merkle_path(MAX_MERKLE_PATH_SIBLINGS + 1);
146
147        assert!(MerklePath::try_from(&oversized).is_err());
148    }
149}