Skip to main content

miden_protocol/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::note::NoteId;
14use crate::{MAX_BATCHES_PER_BLOCK, MAX_OUTPUT_NOTES_PER_BATCH};
15
16/// Contains information about the location of a note.
17#[derive(Clone, Debug, PartialEq, Eq)]
18pub struct NoteLocation {
19    /// The block number the note was created in.
20    block_num: BlockNumber,
21
22    /// The index of the note in the [`BlockNoteTree`](crate::block::BlockNoteTree) of the block
23    /// the note was created in.
24    block_note_tree_index: u16,
25}
26
27impl NoteLocation {
28    /// Returns the block number the note was created in.
29    pub fn block_num(&self) -> BlockNumber {
30        self.block_num
31    }
32
33    /// Returns the index of the note in the [`BlockNoteTree`](crate::block::BlockNoteTree) of the
34    /// block the note was created in.
35    ///
36    /// # Note
37    ///
38    /// The height of the Merkle tree is [crate::constants::BLOCK_NOTE_TREE_DEPTH].
39    /// Thus, the maximum index is `2 ^ BLOCK_NOTE_TREE_DEPTH - 1`.
40    pub fn block_note_tree_index(&self) -> u16 {
41        self.block_note_tree_index
42    }
43}
44
45/// Contains the data required to prove inclusion of a note in the canonical chain.
46#[derive(Clone, Debug, PartialEq, Eq)]
47pub struct NoteInclusionProof {
48    /// Details about the note's location.
49    location: NoteLocation,
50
51    /// The note's authentication Merkle path its block's the note root.
52    note_path: SparseMerklePath,
53}
54
55impl NoteInclusionProof {
56    /// Returns a new [NoteInclusionProof].
57    pub fn new(
58        block_num: BlockNumber,
59        block_note_tree_index: u16,
60        note_path: SparseMerklePath,
61    ) -> Result<Self, NoteError> {
62        const HIGHEST_INDEX: usize = MAX_BATCHES_PER_BLOCK * MAX_OUTPUT_NOTES_PER_BATCH - 1;
63        if block_note_tree_index as usize > HIGHEST_INDEX {
64            return Err(NoteError::BlockNoteTreeIndexOutOfBounds {
65                block_note_tree_index,
66                highest_index: HIGHEST_INDEX,
67            });
68        }
69
70        let location = NoteLocation { block_num, block_note_tree_index };
71
72        Ok(Self { location, note_path })
73    }
74
75    // ACCESSORS
76    // --------------------------------------------------------------------------------------------
77
78    /// Returns the location of the note.
79    pub fn location(&self) -> &NoteLocation {
80        &self.location
81    }
82
83    /// Returns the Sparse Merkle path to the note in the note Merkle tree of the block the note was
84    /// created in.
85    pub fn note_path(&self) -> &SparseMerklePath {
86        &self.note_path
87    }
88
89    /// Returns an iterator over inner nodes of this proof assuming that `note_id` is the value of
90    /// the node to which this proof opens.
91    pub fn authenticated_nodes(&self, note_id: NoteId) -> 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.block_note_tree_index().into(), note_id.as_word())
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.block_note_tree_index);
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 block_note_tree_index = source.read_u16()?;
113
114        Ok(Self { block_num, block_note_tree_index })
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}