miden_objects/note/
location.rs

1use miden_crypto::merkle::SparseMerklePath;
2
3use super::{
4    ByteReader,
5    ByteWriter,
6    Deserializable,
7    DeserializationError,
8    NoteError,
9    Serializable,
10};
11use crate::block::BlockNumber;
12use crate::crypto::merkle::InnerNodeInfo;
13use crate::{MAX_BATCHES_PER_BLOCK, MAX_OUTPUT_NOTES_PER_BATCH, Word};
14
15/// Contains information about the location of a note.
16#[derive(Clone, Debug, PartialEq, Eq)]
17pub struct NoteLocation {
18    /// The block number the note was created in.
19    block_num: BlockNumber,
20
21    /// The index of the note in the note Merkle tree of the block the note was created in.
22    node_index_in_block: u16,
23}
24
25impl NoteLocation {
26    /// Returns the block number the note was created in.
27    pub fn block_num(&self) -> BlockNumber {
28        self.block_num
29    }
30
31    /// Returns the index of the note in the note Merkle tree of the block the note was created in.
32    ///
33    /// # Note
34    ///
35    /// The height of the Merkle tree is [crate::constants::BLOCK_NOTE_TREE_DEPTH].
36    /// Thus, the maximum index is `2 ^ BLOCK_NOTE_TREE_DEPTH - 1`.
37    pub fn node_index_in_block(&self) -> u16 {
38        self.node_index_in_block
39    }
40}
41
42/// Contains the data required to prove inclusion of a note in the canonical chain.
43#[derive(Clone, Debug, PartialEq, Eq)]
44pub struct NoteInclusionProof {
45    /// Details about the note's location.
46    location: NoteLocation,
47
48    /// The note's authentication Merkle path its block's the note root.
49    note_path: SparseMerklePath,
50}
51
52impl NoteInclusionProof {
53    /// Returns a new [NoteInclusionProof].
54    pub fn new(
55        block_num: BlockNumber,
56        node_index_in_block: u16,
57        note_path: SparseMerklePath,
58    ) -> Result<Self, NoteError> {
59        const HIGHEST_INDEX: usize = MAX_BATCHES_PER_BLOCK * MAX_OUTPUT_NOTES_PER_BATCH - 1;
60        if node_index_in_block as usize > HIGHEST_INDEX {
61            return Err(NoteError::NoteLocationIndexOutOfBounds {
62                node_index_in_block,
63                highest_index: HIGHEST_INDEX,
64            });
65        }
66
67        let location = NoteLocation { block_num, node_index_in_block };
68
69        Ok(Self { location, note_path })
70    }
71
72    // ACCESSORS
73    // --------------------------------------------------------------------------------------------
74
75    /// Returns the location of the note.
76    pub fn location(&self) -> &NoteLocation {
77        &self.location
78    }
79
80    /// Returns the Sparse Merkle path to the note in the note Merkle tree of the block the note was
81    /// created in.
82    pub fn note_path(&self) -> &SparseMerklePath {
83        &self.note_path
84    }
85
86    /// Returns an iterator over inner nodes of this proof assuming that `note_commitment` is the
87    /// value of the node to which this proof opens.
88    pub fn authenticated_nodes(
89        &self,
90        note_commitment: Word,
91    ) -> impl Iterator<Item = InnerNodeInfo> {
92        // SAFETY: expect() is fine here because we check index consistency in the constructor
93        self.note_path
94            .authenticated_nodes(self.location.node_index_in_block().into(), note_commitment)
95            .expect("note index is not out of bounds")
96    }
97}
98
99// SERIALIZATION
100// ================================================================================================
101
102impl Serializable for NoteLocation {
103    fn write_into<W: ByteWriter>(&self, target: &mut W) {
104        target.write(self.block_num);
105        target.write_u16(self.node_index_in_block);
106    }
107}
108
109impl Deserializable for NoteLocation {
110    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
111        let block_num = source.read()?;
112        let node_index_in_block = source.read_u16()?;
113
114        Ok(Self { block_num, node_index_in_block })
115    }
116}
117
118impl Serializable for NoteInclusionProof {
119    fn write_into<W: ByteWriter>(&self, target: &mut W) {
120        self.location.write_into(target);
121        self.note_path.write_into(target);
122    }
123}
124
125impl Deserializable for NoteInclusionProof {
126    fn read_from<R: ByteReader>(source: &mut R) -> Result<Self, DeserializationError> {
127        let location = NoteLocation::read_from(source)?;
128        let note_path = SparseMerklePath::read_from(source)?;
129
130        Ok(Self { location, note_path })
131    }
132}