1use std::collections::BTreeMap;
2use std::ops::RangeInclusive;
3
4use miden_objects::account::AccountId;
5use miden_objects::block::{
6 BlockHeader,
7 BlockInputs,
8 BlockNumber,
9 FeeParameters,
10 NullifierWitness,
11};
12use miden_objects::note::{NoteId, NoteInclusionProof};
13use miden_objects::transaction::PartialBlockchain;
14use miden_objects::utils::{Deserializable, Serializable};
15use thiserror::Error;
16
17use crate::errors::{ConversionError, MissingFieldHelper};
18use crate::{AccountWitnessRecord, NullifierWitnessRecord, generated as proto};
19
20impl From<BlockNumber> for proto::blockchain::BlockNumber {
24 fn from(value: BlockNumber) -> Self {
25 proto::blockchain::BlockNumber { block_num: value.as_u32() }
26 }
27}
28
29impl From<proto::blockchain::BlockNumber> for BlockNumber {
30 fn from(value: proto::blockchain::BlockNumber) -> Self {
31 BlockNumber::from(value.block_num)
32 }
33}
34
35impl From<&BlockHeader> for proto::blockchain::BlockHeader {
39 fn from(header: &BlockHeader) -> Self {
40 Self {
41 version: header.version(),
42 prev_block_commitment: Some(header.prev_block_commitment().into()),
43 block_num: header.block_num().as_u32(),
44 chain_commitment: Some(header.chain_commitment().into()),
45 account_root: Some(header.account_root().into()),
46 nullifier_root: Some(header.nullifier_root().into()),
47 note_root: Some(header.note_root().into()),
48 tx_commitment: Some(header.tx_commitment().into()),
49 tx_kernel_commitment: Some(header.tx_kernel_commitment().into()),
50 proof_commitment: Some(header.proof_commitment().into()),
51 timestamp: header.timestamp(),
52 fee_parameters: Some(header.fee_parameters().into()),
53 }
54 }
55}
56
57impl From<BlockHeader> for proto::blockchain::BlockHeader {
58 fn from(header: BlockHeader) -> Self {
59 (&header).into()
60 }
61}
62
63impl TryFrom<&proto::blockchain::BlockHeader> for BlockHeader {
64 type Error = ConversionError;
65
66 fn try_from(value: &proto::blockchain::BlockHeader) -> Result<Self, Self::Error> {
67 value.try_into()
68 }
69}
70
71impl TryFrom<proto::blockchain::BlockHeader> for BlockHeader {
72 type Error = ConversionError;
73
74 fn try_from(value: proto::blockchain::BlockHeader) -> Result<Self, Self::Error> {
75 Ok(BlockHeader::new(
76 value.version,
77 value
78 .prev_block_commitment
79 .ok_or(proto::blockchain::BlockHeader::missing_field(stringify!(
80 prev_block_commitment
81 )))?
82 .try_into()?,
83 value.block_num.into(),
84 value
85 .chain_commitment
86 .ok_or(proto::blockchain::BlockHeader::missing_field(stringify!(chain_commitment)))?
87 .try_into()?,
88 value
89 .account_root
90 .ok_or(proto::blockchain::BlockHeader::missing_field(stringify!(account_root)))?
91 .try_into()?,
92 value
93 .nullifier_root
94 .ok_or(proto::blockchain::BlockHeader::missing_field(stringify!(nullifier_root)))?
95 .try_into()?,
96 value
97 .note_root
98 .ok_or(proto::blockchain::BlockHeader::missing_field(stringify!(note_root)))?
99 .try_into()?,
100 value
101 .tx_commitment
102 .ok_or(proto::blockchain::BlockHeader::missing_field(stringify!(tx_commitment)))?
103 .try_into()?,
104 value
105 .tx_kernel_commitment
106 .ok_or(proto::blockchain::BlockHeader::missing_field(stringify!(
107 tx_kernel_commitment
108 )))?
109 .try_into()?,
110 value
111 .proof_commitment
112 .ok_or(proto::blockchain::BlockHeader::missing_field(stringify!(proof_commitment)))?
113 .try_into()?,
114 FeeParameters::try_from(value.fee_parameters.ok_or(
115 proto::blockchain::FeeParameters::missing_field(stringify!(fee_parameters)),
116 )?)?,
117 value.timestamp,
118 ))
119 }
120}
121
122impl From<BlockInputs> for proto::block_producer_store::BlockInputs {
126 fn from(inputs: BlockInputs) -> Self {
127 let (
128 prev_block_header,
129 partial_block_chain,
130 account_witnesses,
131 nullifier_witnesses,
132 unauthenticated_note_proofs,
133 ) = inputs.into_parts();
134
135 proto::block_producer_store::BlockInputs {
136 latest_block_header: Some(prev_block_header.into()),
137 account_witnesses: account_witnesses
138 .into_iter()
139 .map(|(id, witness)| AccountWitnessRecord { account_id: id, witness }.into())
140 .collect(),
141 nullifier_witnesses: nullifier_witnesses
142 .into_iter()
143 .map(|(nullifier, witness)| {
144 let proof = witness.into_proof();
145 NullifierWitnessRecord { nullifier, proof }.into()
146 })
147 .collect(),
148 partial_block_chain: partial_block_chain.to_bytes(),
149 unauthenticated_note_proofs: unauthenticated_note_proofs
150 .iter()
151 .map(proto::note::NoteInclusionInBlockProof::from)
152 .collect(),
153 }
154 }
155}
156
157impl TryFrom<proto::block_producer_store::BlockInputs> for BlockInputs {
158 type Error = ConversionError;
159
160 fn try_from(response: proto::block_producer_store::BlockInputs) -> Result<Self, Self::Error> {
161 let latest_block_header: BlockHeader = response
162 .latest_block_header
163 .ok_or(proto::blockchain::BlockHeader::missing_field("block_header"))?
164 .try_into()?;
165
166 let account_witnesses = response
167 .account_witnesses
168 .into_iter()
169 .map(|entry| {
170 let witness_record: AccountWitnessRecord = entry.try_into()?;
171 Ok((witness_record.account_id, witness_record.witness))
172 })
173 .collect::<Result<BTreeMap<_, _>, ConversionError>>()?;
174
175 let nullifier_witnesses = response
176 .nullifier_witnesses
177 .into_iter()
178 .map(|entry| {
179 let witness: NullifierWitnessRecord = entry.try_into()?;
180 Ok((witness.nullifier, NullifierWitness::new(witness.proof)))
181 })
182 .collect::<Result<BTreeMap<_, _>, ConversionError>>()?;
183
184 let unauthenticated_note_proofs = response
185 .unauthenticated_note_proofs
186 .iter()
187 .map(<(NoteId, NoteInclusionProof)>::try_from)
188 .collect::<Result<_, ConversionError>>()?;
189
190 let partial_block_chain = PartialBlockchain::read_from_bytes(&response.partial_block_chain)
191 .map_err(|source| {
192 ConversionError::deserialization_error("PartialBlockchain", source)
193 })?;
194
195 Ok(BlockInputs::new(
196 latest_block_header,
197 partial_block_chain,
198 account_witnesses,
199 nullifier_witnesses,
200 unauthenticated_note_proofs,
201 ))
202 }
203}
204
205impl TryFrom<proto::blockchain::FeeParameters> for FeeParameters {
209 type Error = ConversionError;
210 fn try_from(fee_params: proto::blockchain::FeeParameters) -> Result<Self, Self::Error> {
211 let native_asset_id = fee_params.native_asset_id.map(AccountId::try_from).ok_or(
212 proto::blockchain::FeeParameters::missing_field(stringify!(native_asset_id)),
213 )??;
214 let fee_params = FeeParameters::new(native_asset_id, fee_params.verification_base_fee)?;
215 Ok(fee_params)
216 }
217}
218
219impl From<FeeParameters> for proto::blockchain::FeeParameters {
220 fn from(value: FeeParameters) -> Self {
221 Self::from(&value)
222 }
223}
224
225impl From<&FeeParameters> for proto::blockchain::FeeParameters {
226 fn from(value: &FeeParameters) -> Self {
227 Self {
228 native_asset_id: Some(value.native_asset_id().into()),
229 verification_base_fee: value.verification_base_fee(),
230 }
231 }
232}
233
234#[derive(Debug, Clone, Error, PartialEq, Eq)]
238pub enum InvalidBlockRange {
239 #[error("start ({start}) greater than end ({end})")]
240 StartGreaterThanEnd { start: BlockNumber, end: BlockNumber },
241 #[error("empty range: start ({start})..end ({end})")]
242 EmptyRange { start: BlockNumber, end: BlockNumber },
243}
244
245impl proto::rpc_store::BlockRange {
246 pub fn into_inclusive_range<T: From<InvalidBlockRange>>(
249 self,
250 fallback: &BlockNumber,
251 ) -> Result<RangeInclusive<BlockNumber>, T> {
252 let block_range = RangeInclusive::new(
253 self.block_from.into(),
254 self.block_to.map_or(*fallback, BlockNumber::from),
255 );
256
257 if block_range.start() > block_range.end() {
258 return Err(InvalidBlockRange::StartGreaterThanEnd {
259 start: *block_range.start(),
260 end: *block_range.end(),
261 }
262 .into());
263 }
264
265 if block_range.is_empty() {
266 return Err(InvalidBlockRange::EmptyRange {
267 start: *block_range.start(),
268 end: *block_range.end(),
269 }
270 .into());
271 }
272
273 Ok(block_range)
274 }
275}
276
277impl From<RangeInclusive<BlockNumber>> for proto::rpc_store::BlockRange {
278 fn from(range: RangeInclusive<BlockNumber>) -> Self {
279 Self {
280 block_from: range.start().as_u32(),
281 block_to: Some(range.end().as_u32()),
282 }
283 }
284}