miden_objects/decoded/
blockchain.rs1use miden_protobuf::unwrap_infallible;
3pub use proto::blockchain::DecodedTrackedMmrLeaf as TrackedMmrLeaf;
4
5use crate::decoded::VerificationError;
6use crate::{Verify, proto};
7
8#[cfg(test)]
9mod tests;
10
11#[cfg(test)]
12pub(crate) mod test_utils;
13
14impl Verify for TrackedMmrLeaf {
15 type Verified = (u64, miden_protocol::Word, alloc::vec::Vec<miden_protocol::Word>);
16 type Error = core::convert::Infallible;
17 fn verify(self) -> Result<Self::Verified, Self::Error> {
18 Ok((self.position, self.leaf, self.path.into_inner()))
19 }
20}
21
22pub use proto::blockchain::DecodedBlockNumber as BlockNumber;
23
24impl Verify for BlockNumber {
25 type Verified = miden_protocol::block::BlockNumber;
26 type Error = core::convert::Infallible;
27 fn verify(self) -> Result<Self::Verified, Self::Error> {
28 Ok(self.block_num.into())
29 }
30}
31
32pub use proto::blockchain::DecodedFeeParameters as FeeParameters;
33
34impl Verify for FeeParameters {
35 type Verified = miden_protocol::block::FeeParameters;
36 type Error = core::convert::Infallible;
37 fn verify(self) -> Result<Self::Verified, Self::Error> {
38 Ok(Self::Verified::new(self.verification_base_fee))
39 }
40}
41
42pub use proto::blockchain::DecodedNextProtocolConfig as NextProtocolConfig;
43
44impl Verify for NextProtocolConfig {
45 type Verified = miden_protocol::protocol_config::NextProtocolConfig;
46 type Error = miden_protocol::errors::ProtocolConfigError;
47 fn verify(self) -> Result<Self::Verified, Self::Error> {
48 let effective_from = unwrap_infallible(self.effective_from.verify());
49 Self::Verified::new(effective_from, self.protocol_config)
50 }
51}
52
53pub use proto::blockchain::DecodedValidatorConfig as ValidatorConfig;
54
55impl Verify for ValidatorConfig {
56 type Verified = miden_protocol::block::ValidatorConfig;
57 type Error = VerificationError;
58 fn verify(self) -> Result<Self::Verified, Self::Error> {
59 let keys = self.keys.verify_infallible();
60 Ok(Self::Verified::new(keys, self.quorum.try_into()?)?)
61 }
62}
63
64pub use proto::blockchain::DecodedBlockHeader as BlockHeader;
65
66impl crate::BuildUnchecked for BlockHeader {
68 type Output = miden_protocol::block::BlockHeader;
69 type Error = VerificationError;
70 fn build_unchecked(self) -> Result<Self::Output, Self::Error> {
71 if self.version != proto::blockchain::BlockVersion::V1 {
72 return Err(BlockHeaderError::UnspecifiedVersion.into());
73 }
74 Ok(Self::Output::new(
75 self.prev_block_commitment,
76 unwrap_infallible(self.block_num.verify()),
77 self.chain_commitment,
78 self.account_root,
79 self.nullifier_root,
80 self.note_root,
81 self.tx_commitment,
82 self.validator_config.verify()?,
83 unwrap_infallible(self.fee_parameters.verify()),
84 self.protocol_config_commitment,
85 self.next_protocol_config.verify()?,
86 self.timestamp,
87 ))
88 }
89}
90
91#[derive(Debug, thiserror::Error)]
92pub enum BlockHeaderError {
93 #[error("block header version is unspecified")]
94 UnspecifiedVersion,
95}
96
97pub use proto::blockchain::DecodedPartialBlockchain as PartialBlockchain;
98
99impl crate::BuildUnchecked for PartialBlockchain {
102 type Output = miden_protocol::transaction::PartialBlockchain;
103 type Error = VerificationError;
104 fn build_unchecked(self) -> Result<Self::Output, Self::Error> {
105 use miden_protocol::crypto::merkle::MerklePath;
106 use miden_protocol::crypto::merkle::mmr::{Forest, MmrPeaks, PartialMmr};
107
108 let size = usize::try_from(self.forest)?;
109 let peaks = MmrPeaks::new(Forest::new(size)?, self.peaks.into_inner())?;
110 let mut mmr = PartialMmr::from_peaks(peaks);
111 let mut previous = None;
112 for tracked in self.tracked_leaves.into_inner() {
113 let position = usize::try_from(tracked.position)?;
114 if position >= size {
115 return Err(PartialBlockchainError::Position { position, size }.into());
116 }
117 if previous.is_some_and(|previous| position <= previous) {
118 return Err(PartialBlockchainError::LeafOrder.into());
119 }
120 previous = Some(position);
121 mmr.track(position, tracked.leaf, &MerklePath::new(tracked.path.into_inner()))?;
122 }
123 let mut previous = None;
124 let mut headers = alloc::vec::Vec::new();
125 for header in self.block_headers.into_inner() {
126 let header = header.build_unchecked()?;
127 if previous.is_some_and(|previous| header.block_num() <= previous) {
128 return Err(PartialBlockchainError::HeaderOrder.into());
129 }
130 previous = Some(header.block_num());
131 headers.push(header);
132 }
133 Ok(Self::Output::new(mmr, headers)?)
134 }
135}
136
137#[derive(Debug, thiserror::Error)]
138pub enum PartialBlockchainError {
139 #[error("tracked leaf position {position} is outside forest of size {size}")]
140 Position { position: usize, size: usize },
141 #[error("tracked leaf positions must be unique and strictly increasing")]
142 LeafOrder,
143 #[error("block headers must be unique and ordered by ascending block number")]
144 HeaderOrder,
145}
146
147pub use proto::blockchain::DecodedBlockAccountUpdate as BlockAccountUpdate;
148
149impl Verify for BlockAccountUpdate {
150 type Verified = miden_protocol::block::BlockAccountUpdate;
151 type Error = VerificationError;
152 fn verify(self) -> Result<Self::Verified, Self::Error> {
153 Ok(Self::Verified::new(
154 self.account_id.verify()?,
155 self.final_state_commitment,
156 self.details.verify()?,
157 )?)
158 }
159}
160
161pub use proto::blockchain::DecodedIndexedOutputNote as IndexedOutputNote;
162
163impl Verify for IndexedOutputNote {
164 type Verified = (usize, miden_protocol::transaction::OutputNote);
165 type Error = VerificationError;
166 fn verify(self) -> Result<Self::Verified, Self::Error> {
167 Ok((self.note_index_in_batch.try_into()?, self.note.verify()?))
168 }
169}
170
171pub use proto::blockchain::DecodedOutputNoteBatch as OutputNoteBatch;
172
173impl Verify for OutputNoteBatch {
174 type Verified = miden_protocol::block::OutputNoteBatch;
175 type Error = VerificationError;
176 fn verify(self) -> Result<Self::Verified, Self::Error> {
177 Ok(self.notes.verify()?)
178 }
179}
180
181pub use proto::blockchain::DecodedBlockBody as BlockBody;
182
183impl crate::BuildUnchecked for BlockBody {
185 type Output = miden_protocol::block::BlockBody;
186 type Error = VerificationError;
187 fn build_unchecked(self) -> Result<Self::Output, Self::Error> {
188 let updates = self.updated_accounts.verify()?;
189 let notes = self.output_note_batches.verify()?;
190 let nullifiers = self.created_nullifiers.map(miden_protocol::note::Nullifier::from_raw);
191 let transactions = self.transactions.build_unchecked()?;
192 Ok(Self::Output::new(
193 updates,
194 notes,
195 nullifiers,
196 miden_protocol::transaction::OrderedTransactionHeaders::new_unchecked(transactions),
197 )?)
198 }
199}
200
201pub use proto::blockchain::DecodedSignedBlock as SignedBlock;
202
203impl crate::BuildUnchecked for SignedBlock {
205 type Output = miden_protocol::block::SignedBlock;
206 type Error = VerificationError;
207 fn build_unchecked(self) -> Result<Self::Output, Self::Error> {
208 self.build(None)
209 }
210}
211
212impl SignedBlock {
213 fn build(
214 self,
215 parent: Option<&miden_protocol::block::BlockHeader>,
216 ) -> Result<miden_protocol::block::SignedBlock, VerificationError> {
217 use crate::BuildUnchecked;
218
219 let header = self.header.build_unchecked()?;
220 let body = self.body.build_unchecked()?;
221 let signatures = self.signatures.verify_infallible();
222 let signatures = miden_protocol::block::BlockSignatures::new(signatures)
223 .map_err(VerificationError::new)?;
224 let block = miden_protocol::block::SignedBlock::new_unchecked(header, body, signatures);
225 block.validate(parent)?;
226 Ok(block)
227 }
228}
229
230impl crate::VerifyWith<&miden_protocol::block::BlockHeader> for SignedBlock {
233 type Verified = miden_protocol::block::SignedBlock;
234 type Error = VerificationError;
235 fn verify_with(
236 self,
237 parent: &miden_protocol::block::BlockHeader,
238 ) -> Result<Self::Verified, Self::Error> {
239 self.build(Some(parent))
240 }
241}